New DWIM commands for changing letter-case
[emacs.git] / src / macfont.m
blob97a255bf018395806f44a7728071d285a8b6a7c2
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2015 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 #include <libkern/OSByteOrder.h>
41 static struct font_driver macfont_driver;
43 static double mac_font_get_advance_width_for_glyph (CTFontRef, CGGlyph);
44 static CGRect mac_font_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
45 static CFArrayRef mac_font_create_available_families (void);
46 static Boolean mac_font_equal_in_postscript_name (CTFontRef, CTFontRef);
47 static CTLineRef mac_font_create_line_with_string_and_font (CFStringRef,
48                                                             CTFontRef);
49 static Boolean mac_font_descriptor_supports_languages (CTFontDescriptorRef,
50                                                        CFArrayRef);
51 static CFStringRef mac_font_create_preferred_family_for_attributes (CFDictionaryRef);
52 static CFIndex mac_font_shape (CTFontRef, CFStringRef,
53                                struct mac_glyph_layout *, CFIndex);
54 static CFArrayRef mac_font_copy_default_descriptors_for_language (CFStringRef);
55 static CFStringRef mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef, CFArrayRef);
56 #if USE_CT_GLYPH_INFO
57 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef, CTCharacterCollection,
58                                              CGFontIndex);
59 #endif
61 struct macfont_metrics;
63 /* The actual structure for Mac font that can be cast to struct font.  */
65 struct macfont_info
67   struct font font;
68   CTFontRef macfont;
69   CGFontRef cgfont;
70   ScreenFontRef screen_font;
71   struct macfont_cache *cache;
72   struct macfont_metrics **metrics;
73   short metrics_nrows;
74   bool_bf synthetic_italic_p : 1;
75   bool_bf synthetic_bold_p : 1;
76   unsigned spacing : 2;
77   unsigned antialias : 2;
78   bool_bf color_bitmap_p : 1;
81 /* Values for the `spacing' member in `struct macfont_info'.  */
83 enum
84   {
85     MACFONT_SPACING_PROPORTIONAL,
86     MACFONT_SPACING_MONO,
87     MACFONT_SPACING_SYNTHETIC_MONO,
88   };
90 /* Values for the `antialias' member in `struct macfont_info'.  */
92 enum
93   {
94     MACFONT_ANTIALIAS_DEFAULT,
95     MACFONT_ANTIALIAS_OFF,
96     MACFONT_ANTIALIAS_ON,
97   };
99 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
100 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
101 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
103 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
104 static const CGFloat synthetic_bold_factor = 0.024;
106 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
107                                                         CTFontSymbolicTraits *);
108 static void macfont_store_descriptor_attributes (CTFontDescriptorRef,
109                                                  Lisp_Object);
110 static Lisp_Object macfont_descriptor_entity (CTFontDescriptorRef, Lisp_Object,
111                                               CTFontSymbolicTraits);
112 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
113 static int macfont_glyph_extents (struct font *, CGGlyph,
114                                   struct font_metrics *, CGFloat *, int);
115 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
116 static Boolean macfont_supports_charset_and_languages_p (CTFontDescriptorRef,
117                                                          CFCharacterSetRef,
118                                                          Lisp_Object,
119                                                          CFArrayRef);
120 static Boolean macfont_closest_traits_index_p (CFArrayRef, CTFontSymbolicTraits,
121                                                CFIndex);
122 static CFDataRef mac_font_copy_uvs_table (CTFontRef);
123 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
124                                               const UTF32Char [],
125                                               CGGlyph [], CFIndex);
127 /* From CFData to a lisp string.  Always returns a unibyte string.  */
129 static Lisp_Object
130 cfdata_to_lisp (CFDataRef data)
132   CFIndex len = CFDataGetLength (data);
133   Lisp_Object result = make_uninit_string (len);
135   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
137   return result;
142 /* From CFString to a lisp string.  Returns a unibyte string
143    containing a UTF-8 byte sequence.  */
145 static Lisp_Object
146 cfstring_to_lisp_nodecode (CFStringRef string)
148   Lisp_Object result = Qnil;
149   CFDataRef data;
150   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
152   if (s)
153     {
154       CFIndex i, length = CFStringGetLength (string);
156       for (i = 0; i < length; i++)
157         if (CFStringGetCharacterAtIndex (string, i) == 0)
158           break;
160       if (i == length)
161         return make_unibyte_string (s, strlen (s));
162     }
164   data = CFStringCreateExternalRepresentation (NULL, string,
165                                                kCFStringEncodingUTF8, '?');
166   if (data)
167     {
168       result = cfdata_to_lisp (data);
169       CFRelease (data);
170     }
172   return result;
175 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
176    cfstring_create_with_utf8_cstring, this function preserves NUL
177    characters.  */
179 static CFStringRef
180 cfstring_create_with_string_noencode (Lisp_Object s)
182   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
183                                                 kCFStringEncodingUTF8, false);
185   if (string == NULL)
186     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
187     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
188                                       kCFStringEncodingMacRoman, false);
190   return string;
193 static CGFloat
194 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
196   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
198   return advancement.width;
201 static CGGlyph
202 mac_font_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
203                             CGFontIndex cid)
205 #if USE_CT_GLYPH_INFO
206   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
207 #else
208   {
209     CGGlyph result = kCGFontIndexInvalid;
210     NSFont *nsFont = (NSFont *) font;
211     unichar characters[] = {0xfffd};
212     NSString *string =
213       [NSString stringWithCharacters:characters
214                               length:ARRAYELTS (characters)];
215     NSGlyphInfo *glyphInfo =
216       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
217                                          collection:collection
218                                          baseString:string];
219     NSDictionary *attributes =
220       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
221                     glyphInfo,NSGlyphInfoAttributeName,nil];
222     NSTextStorage *textStorage =
223       [[NSTextStorage alloc] initWithString:string
224                                  attributes:attributes];
225     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
226     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
227     NSFont *fontInTextStorage;
229     [layoutManager addTextContainer:textContainer];
230     [textContainer release];
231     [textStorage addLayoutManager:layoutManager];
232     [layoutManager release];
234     /* Force layout.  */
235     (void) [layoutManager glyphRangeForTextContainer:textContainer];
237     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
238                                 effectiveRange:NULL];
239     if (fontInTextStorage == nsFont
240         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
241       {
242         NSGlyph glyph = [layoutManager glyphAtIndex:0];
244         if (glyph < [nsFont numberOfGlyphs])
245           result = glyph;
246       }
248     [textStorage release];
250     return result;
251   }
253 #endif
255 static ScreenFontRef
256 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
258   NSFont *result, *font;
260   font = [NSFont fontWithName:((NSString *) name) size:size];
261   result = [font screenFont];
263   return (ScreenFontRef)[result retain];
267 static Boolean
268 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
269                              CGFloat *descent, CGFloat *leading)
271   NSFont *nsFont = [(NSFont *)font printerFont];
272   NSTextStorage *textStorage;
273   NSLayoutManager *layoutManager;
274   NSTextContainer *textContainer;
275   NSRect usedRect;
276   NSPoint spaceLocation;
277   CGFloat descender;
279   textStorage = [[NSTextStorage alloc] initWithString:@" "];
280   layoutManager = [[NSLayoutManager alloc] init];
281   textContainer = [[NSTextContainer alloc] init];
283   [textStorage setFont:nsFont];
284   [textContainer setLineFragmentPadding:0];
285   [layoutManager setUsesScreenFonts:YES];
287   [layoutManager addTextContainer:textContainer];
288   [textContainer release];
289   [textStorage addLayoutManager:layoutManager];
290   [layoutManager release];
292   if (!(textStorage && layoutManager && textContainer))
293     {
294       [textStorage release];
296       return false;
297     }
299   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
300                                                  effectiveRange:NULL];
301   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
302   [textStorage release];
304   *ascent = spaceLocation.y;
305   *descent = NSHeight (usedRect) - spaceLocation.y;
306   *leading = 0;
307   descender = [nsFont descender];
308   if (- descender < *descent)
309     {
310       *leading = *descent + descender;
311       *descent = - descender;
312     }
314   return true;
317 static CFIndex
318 mac_font_shape_1 (NSFont *font, NSString *string,
319                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
320                   BOOL screen_font_p)
322   NSUInteger i;
323   CFIndex result = 0;
324   NSTextStorage *textStorage;
325   NSLayoutManager *layoutManager;
326   NSTextContainer *textContainer;
327   NSUInteger stringLength;
328   NSPoint spaceLocation;
329   NSUInteger used, numberOfGlyphs;
331   textStorage = [[NSTextStorage alloc] initWithString:string];
332   layoutManager = [[NSLayoutManager alloc] init];
333   textContainer = [[NSTextContainer alloc] init];
335   /* Append a trailing space to measure baseline position.  */
336   [textStorage appendAttributedString:([[[NSAttributedString alloc]
337                                           initWithString:@" "] autorelease])];
338   [textStorage setFont:font];
339   [textContainer setLineFragmentPadding:0];
340   [layoutManager setUsesScreenFonts:screen_font_p];
342   [layoutManager addTextContainer:textContainer];
343   [textContainer release];
344   [textStorage addLayoutManager:layoutManager];
345   [layoutManager release];
347   if (!(textStorage && layoutManager && textContainer))
348     {
349       [textStorage release];
351       return 0;
352     }
354   stringLength = [string length];
356   /* Force layout.  */
357   (void) [layoutManager glyphRangeForTextContainer:textContainer];
359   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
361   /* Remove the appended trailing space because otherwise it may
362      generate a wrong result for a right-to-left text.  */
363   [textStorage beginEditing];
364   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
365   [textStorage endEditing];
366   (void) [layoutManager glyphRangeForTextContainer:textContainer];
368   i = 0;
369   while (i < stringLength)
370     {
371       NSRange range;
372       NSFont *fontInTextStorage =
373         [textStorage attribute:NSFontAttributeName atIndex:i
374                      longestEffectiveRange:&range
375                        inRange:(NSMakeRange (0, stringLength))];
377       if (!(fontInTextStorage == font
378             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
379         break;
380       i = NSMaxRange (range);
381     }
382   if (i < stringLength)
383     /* Make the test `used <= glyph_len' below fail if textStorage
384        contained some fonts other than the specified one.  */
385     used = glyph_len + 1;
386   else
387     {
388       NSRange range = NSMakeRange (0, stringLength);
390       range = [layoutManager glyphRangeForCharacterRange:range
391                                     actualCharacterRange:NULL];
392       numberOfGlyphs = NSMaxRange (range);
393       used = numberOfGlyphs;
394       for (i = 0; i < numberOfGlyphs; i++)
395         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
396           used--;
397     }
399   if (0 < used && used <= glyph_len)
400     {
401       NSUInteger glyphIndex, prevGlyphIndex;
402       unsigned char bidiLevel;
403       NSUInteger *permutation;
404       NSRange compRange, range;
405       CGFloat totalAdvance;
407       glyphIndex = 0;
408       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
409         glyphIndex++;
411       /* For now we assume the direction is not changed within the
412          string.  */
413       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
414                                glyphs:NULL characterIndexes:NULL
415                     glyphInscriptions:NULL elasticBits:NULL
416                            bidiLevels:&bidiLevel];
417       if (bidiLevel & 1)
418         permutation = xmalloc (sizeof (NSUInteger) * used);
419       else
420         permutation = NULL;
422 #define RIGHT_TO_LEFT_P permutation
424       /* Fill the `comp_range' member of struct mac_glyph_layout, and
425          setup a permutation for right-to-left text.  */
426       compRange = NSMakeRange (0, 0);
427       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
428            range.length++)
429         {
430           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
431           NSUInteger characterIndex =
432             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
434           gl->string_index = characterIndex;
436           if (characterIndex >= NSMaxRange (compRange))
437             {
438               compRange.location = NSMaxRange (compRange);
439               do
440                 {
441                   NSRange characterRange =
442                     [string
443                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
445                   compRange.length =
446                     NSMaxRange (characterRange) - compRange.location;
447                   [layoutManager glyphRangeForCharacterRange:compRange
448                                         actualCharacterRange:&characterRange];
449                   characterIndex = NSMaxRange (characterRange) - 1;
450                 }
451               while (characterIndex >= NSMaxRange (compRange));
453               if (RIGHT_TO_LEFT_P)
454                 for (i = 0; i < range.length; i++)
455                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
457               range = NSMakeRange (NSMaxRange (range), 0);
458             }
460           gl->comp_range.location = compRange.location;
461           gl->comp_range.length = compRange.length;
463           while (++glyphIndex < numberOfGlyphs)
464             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
465               break;
466         }
467       if (RIGHT_TO_LEFT_P)
468         for (i = 0; i < range.length; i++)
469           permutation[range.location + i] = NSMaxRange (range) - i - 1;
471       /* Then fill the remaining members.  */
472       glyphIndex = prevGlyphIndex = 0;
473       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
474         glyphIndex++;
476       if (!RIGHT_TO_LEFT_P)
477         totalAdvance = 0;
478       else
479         {
480           NSUInteger nrects;
481           NSRect *glyphRects =
482             [layoutManager
483               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
484               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
485                      inTextContainer:textContainer rectCount:&nrects];
487           totalAdvance = NSMaxX (glyphRects[0]);
488         }
490       for (i = 0; i < used; i++)
491         {
492           struct mac_glyph_layout *gl;
493           NSPoint location;
494           NSUInteger nextGlyphIndex;
495           NSRange glyphRange;
496           NSRect *glyphRects;
497           NSUInteger nrects;
499           if (!RIGHT_TO_LEFT_P)
500             gl = glyph_layouts + i;
501           else
502             {
503               NSUInteger dest = permutation[i];
505               gl = glyph_layouts + dest;
506               if (i < dest)
507                 {
508                   CFIndex tmp = gl->string_index;
510                   gl->string_index = glyph_layouts[i].string_index;
511                   glyph_layouts[i].string_index = tmp;
512                 }
513             }
514           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
516           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
517           gl->baseline_delta = spaceLocation.y - location.y;
519           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
520                nextGlyphIndex++)
521             if (![layoutManager
522                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
523               break;
525           if (!RIGHT_TO_LEFT_P)
526             {
527               CGFloat maxX;
529               if (prevGlyphIndex == 0)
530                 glyphRange = NSMakeRange (0, nextGlyphIndex);
531               else
532                 glyphRange = NSMakeRange (glyphIndex,
533                                           nextGlyphIndex - glyphIndex);
534               glyphRects =
535                 [layoutManager
536                   rectArrayForGlyphRange:glyphRange
537                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
538                          inTextContainer:textContainer rectCount:&nrects];
539               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
540               gl->advance_delta = location.x - totalAdvance;
541               gl->advance = maxX - totalAdvance;
542               totalAdvance = maxX;
543             }
544           else
545             {
546               CGFloat minX;
548               if (nextGlyphIndex == numberOfGlyphs)
549                 glyphRange = NSMakeRange (prevGlyphIndex,
550                                           numberOfGlyphs - prevGlyphIndex);
551               else
552                 glyphRange = NSMakeRange (prevGlyphIndex,
553                                           glyphIndex + 1 - prevGlyphIndex);
554               glyphRects =
555                 [layoutManager
556                   rectArrayForGlyphRange:glyphRange
557                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
558                          inTextContainer:textContainer rectCount:&nrects];
559               minX = min (NSMinX (glyphRects[0]), totalAdvance);
560               gl->advance = totalAdvance - minX;
561               totalAdvance = minX;
562               gl->advance_delta = location.x - totalAdvance;
563             }
565           prevGlyphIndex = glyphIndex + 1;
566           glyphIndex = nextGlyphIndex;
567         }
569       if (RIGHT_TO_LEFT_P)
570         xfree (permutation);
572 #undef RIGHT_TO_LEFT_P
574       result = used;
575     }
576   [textStorage release];
578   return result;
581 static CFIndex
582 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
583                        struct mac_glyph_layout *glyph_layouts,
584                        CFIndex glyph_len)
586   return mac_font_shape_1 ([(NSFont *)font printerFont],
587                            (NSString *) string,
588                            glyph_layouts, glyph_len, YES);
591 static CGColorRef
592 get_cgcolor(unsigned long idx, struct frame *f)
594   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
595   [nsColor set];
596   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
597   NSInteger noc = [nsColor numberOfComponents];
598   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
599   CGColorRef cgColor;
601   [nsColor getComponents: components];
602   cgColor = CGColorCreate (colorSpace, components);
603   xfree (components);
604   return cgColor;
607 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
608   do {                                                                  \
609     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
610     CGContextSetFillColorWithColor (context, refcol_) ;                 \
611     CGColorRelease (refcol_);                                           \
612   } while (0)
613 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
614   do {                                                                  \
615     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
616     CGContextSetFillColorWithColor (context, refcol_);                  \
617     CGColorRelease (refcol_);                                           \
618   } while (0)
619 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
620   do {                                                                  \
621     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
622     CGContextSetStrokeColorWithColor (context, refcol_);                \
623     CGColorRelease (refcol_);                                           \
624   } while (0)
628 /* Mac font driver.  */
630 static struct
632   /* registry name */
633   const char *name;
634   /* characters to distinguish the charset from the others */
635   int uniquifier[6];
636   /* additional constraint by language */
637   CFStringRef lang;
638   /* set on demand */
639   CFCharacterSetRef cf_charset;
640   CFStringRef cf_charset_string;
641 } cf_charset_table[] =
642   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
643     { "iso8859-2", { 0x00A0, 0x010E }},
644     { "iso8859-3", { 0x00A0, 0x0108 }},
645     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
646     { "iso8859-5", { 0x00A0, 0x0401 }},
647     { "iso8859-6", { 0x00A0, 0x060C }},
648     { "iso8859-7", { 0x00A0, 0x0384 }},
649     { "iso8859-8", { 0x00A0, 0x05D0 }},
650     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
651     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
652     { "iso8859-11", { 0x00A0, 0x0E01 }},
653     { "iso8859-13", { 0x00A0, 0x201C }},
654     { "iso8859-14", { 0x00A0, 0x0174 }},
655     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
656     { "iso8859-16", { 0x00A0, 0x0218}},
657     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
658     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
659     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
660     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
661     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
662     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
663     { "cns11643.1992-3", { 0x201A9 }},
664     { "cns11643.1992-4", { 0x20057 }},
665     { "cns11643.1992-5", { 0x20000 }},
666     { "cns11643.1992-6", { 0x20003 }},
667     { "cns11643.1992-7", { 0x20055 }},
668     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
669     { "jisx0212.1990-0", { 0x4E44 }},
670     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
671     { "jisx0213.2000-2", { 0xFA49 }},
672     { "jisx0213.2004-1", { 0x20B9F }},
673     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
674     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
675     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
676     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
677     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
678     { "unicode-sip", { 0x20000 }},
679     { NULL }
680   };
682 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
683 static const struct
685   CFStringRef language;
686   CFStringRef font_names[3];
687 } macfont_language_default_font_names[] = {
688   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
689                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
690                     NULL }},
691   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
692                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
693                     NULL }},
694   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
695                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
696                          NULL }},
697   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
698                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
699                          NULL }},
700   { NULL }
702 #endif
704 static CGFloat macfont_antialias_threshold;
706 void
707 macfont_update_antialias_threshold (void)
709   int threshold;
710   Boolean valid_p;
712   threshold =
713     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
714                                      kCFPreferencesCurrentApplication,
715                                      &valid_p);
716   if (valid_p)
717     macfont_antialias_threshold = threshold;
720 static inline Lisp_Object
721 macfont_intern_prop_cfstring (CFStringRef cfstring)
723   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
725   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
728 static inline CFIndex
729 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
731   if (c < 0x10000)
732     {
733       unichars[0] = c;
735       return 1;
736     }
737   else
738     {
739       c -= 0x10000;
740       unichars[0] = (c >> 10) + 0xD800;
741       unichars[1] = (c & 0x3FF) + 0xDC00;
743       return 2;
744     }
747 static Boolean
748 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
749                                          CTFontSymbolicTraits *sym_traits)
751   SInt64 sint64_value;
753   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
754      OS X 10.6 when the value is greater than or equal to 1 << 31.  */
755   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
756     {
757       *sym_traits = (CTFontSymbolicTraits) sint64_value;
759       return true;
760     }
762   return false;
765 static void
766 macfont_store_descriptor_attributes (CTFontDescriptorRef desc,
767                                      Lisp_Object spec_or_entity)
769   CFStringRef str;
770   CFDictionaryRef dict;
771   CFNumberRef num;
772   CGFloat floatval;
774   str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
775   if (str)
776     {
777       ASET (spec_or_entity, FONT_FAMILY_INDEX,
778             macfont_intern_prop_cfstring (str));
779       CFRelease (str);
780     }
781   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
782   if (dict)
783     {
784       struct {
785         enum font_property_index index;
786         CFStringRef trait;
787         CGPoint points[6];
788       } numeric_traits[] =
789           {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
790             {{-0.4, 50},        /* light */
791              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
792              {0, 100},          /* normal */
793              {0.24, 140},       /* (semi-bold + normal) / 2 */
794              {0.4, 200},        /* bold */
795              {CGFLOAT_MAX, CGFLOAT_MAX}}},
796            {FONT_SLANT_INDEX, kCTFontSlantTrait,
797             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
798            {FONT_WIDTH_INDEX, kCTFontWidthTrait,
799             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
800       int i;
802       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
803         {
804           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
805           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
806             {
807               CGPoint *point = numeric_traits[i].points;
809               while (point->x < floatval)
810                 point++;
811               if (point == numeric_traits[i].points)
812                 point++;
813               else if (point->x == CGFLOAT_MAX)
814                 point--;
815               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
816                                            * ((point->y - (point - 1)->y)
817                                               / (point->x - (point - 1)->x)));
818               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
819                               make_number (lround (floatval)));
820             }
821         }
823       num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
824       if (num)
825         {
826           CTFontSymbolicTraits sym_traits;
827           int spacing;
829           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
830           spacing = (sym_traits & kCTFontTraitMonoSpace
831                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
832           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
833         }
835       CFRelease (dict);
836     }
837   num = CTFontDescriptorCopyAttribute (desc, kCTFontSizeAttribute);
838   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
839     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
840   else
841     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
842   if (num)
843     CFRelease (num);
846 static Lisp_Object
847 macfont_descriptor_entity (CTFontDescriptorRef desc, Lisp_Object extra,
848                            CTFontSymbolicTraits synth_sym_traits)
850   Lisp_Object entity;
851   CFDictionaryRef dict;
852   CTFontSymbolicTraits sym_traits = 0;
853   CFStringRef name;
855   entity = font_make_entity ();
857   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
858   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
860   macfont_store_descriptor_attributes (desc, entity);
862   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
863   if (dict)
864     {
865       CFNumberRef num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
867       if (num)
868         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
869       CFRelease (dict);
870     }
871   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
872     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
873   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
874   name = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
875   font_put_extra (entity, QCfont_entity,
876                   make_save_ptr_int ((void *) name, sym_traits));
877   if (synth_sym_traits & kCTFontTraitItalic)
878     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
879                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
880   if (synth_sym_traits & kCTFontTraitBold)
881     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
882                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
883   if (synth_sym_traits & kCTFontTraitMonoSpace)
884     ASET (entity, FONT_SPACING_INDEX,
885           make_number (FONT_SPACING_SYNTHETIC_MONO));
887   return entity;
890 /* Cache for font family name symbols vs CFStrings.  A value of nil
891 means the cache has been invalidated.  Otherwise the value is a Lisp
892 hash table whose keys are symbols and the value for a key is either
893 nil (no corresponding family name) or a Lisp save value wrapping the
894 corresponding family name in CFString.  */
896 static Lisp_Object macfont_family_cache;
898 static void
899 macfont_invalidate_family_cache (void)
901   if (HASH_TABLE_P (macfont_family_cache))
902     {
903       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
904       ptrdiff_t i, size = HASH_TABLE_SIZE (h);
906       for (i = 0; i < size; ++i)
907         if (!NILP (HASH_HASH (h, i)))
908           {
909             Lisp_Object value = HASH_VALUE (h, i);
911             if (SAVE_VALUEP (value))
912               CFRelease (XSAVE_POINTER (value, 0));
913           }
914       macfont_family_cache = Qnil;
915     }
918 static bool
919 macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
921   if (HASH_TABLE_P (macfont_family_cache))
922     {
923       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
924       ptrdiff_t i = hash_lookup (h, symbol, NULL);
926       if (i >= 0)
927         {
928           Lisp_Object value = HASH_VALUE (h, i);
930           *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
932           return true;
933         }
934     }
936   return false;
939 static void
940 macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
942   struct Lisp_Hash_Table *h;
943   ptrdiff_t i;
944   EMACS_UINT hash;
945   Lisp_Object value;
947   if (!HASH_TABLE_P (macfont_family_cache))
948     macfont_family_cache = CALLN (Fmake_hash_table, QCtest, Qeq);
950   h = XHASH_TABLE (macfont_family_cache);
951   i = hash_lookup (h, symbol, &hash);
952   value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
953   if (i >= 0)
954     {
955       Lisp_Object old_value = HASH_VALUE (h, i);
957       if (SAVE_VALUEP (old_value))
958         CFRelease (XSAVE_POINTER (old_value, 0));
959       set_hash_value_slot (h, i, value);
960     }
961   else
962     hash_put (h, symbol, value, hash);
965 /* Cache of all the available font family names except "LastResort"
966 and those start with ".".  NULL means the cache has been invalidated.
967 Otherwise, the value is CFArray of CFStrings and the elements are
968 sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
969 OS X 10.6 and later).  */
971 static CFArrayRef macfont_available_families_cache = NULL;
973 static void
974 macfont_invalidate_available_families_cache (void)
976   if (macfont_available_families_cache)
977     {
978       CFRelease (macfont_available_families_cache);
979       macfont_available_families_cache = NULL;
980     }
983 static void
984 macfont_handle_font_change_notification (CFNotificationCenterRef center,
985                                          void *observer,
986                                          CFStringRef name, const void *object,
987                                          CFDictionaryRef userInfo)
989   macfont_invalidate_family_cache ();
990   macfont_invalidate_available_families_cache ();
993 static void
994 macfont_init_font_change_handler (void)
996   static bool initialized = false;
998   if (initialized)
999     return;
1001   initialized = true;
1002   CFNotificationCenterAddObserver
1003     (CFNotificationCenterGetLocalCenter (), NULL,
1004      macfont_handle_font_change_notification,
1005      kCTFontManagerRegisteredFontsChangedNotification,
1006      NULL, CFNotificationSuspensionBehaviorCoalesce);
1009 static CFArrayRef
1010 macfont_copy_available_families_cache (void)
1012   macfont_init_font_change_handler ();
1014   if (macfont_available_families_cache == NULL)
1015     macfont_available_families_cache = mac_font_create_available_families ();
1017   return (macfont_available_families_cache
1018           ? CFRetain (macfont_available_families_cache) : NULL);
1021 static CFStringRef
1022 macfont_create_family_with_symbol (Lisp_Object symbol)
1024   CFStringRef result = NULL, family_name;
1025   CFDictionaryRef attributes = NULL;
1026   CTFontDescriptorRef pat_desc = NULL;
1028   if (macfont_get_family_cache_if_present (symbol, &result))
1029     return result ? CFRetain (result) : NULL;
1031   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1032   if (family_name)
1033     {
1034       attributes =
1035         CFDictionaryCreate (NULL,
1036                             (const void **) &kCTFontFamilyNameAttribute,
1037                             (const void **) &family_name, 1,
1038                             &kCFTypeDictionaryKeyCallBacks,
1039                             &kCFTypeDictionaryValueCallBacks);
1040       CFRelease (family_name);
1041     }
1042   if (attributes)
1043     {
1044       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
1045       CFRelease (attributes);
1046     }
1047   if (pat_desc)
1048     {
1049       CTFontDescriptorRef desc =
1050         CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
1052       if (desc)
1053         {
1054           result =
1055             CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
1056           CFRelease (desc);
1057         }
1058       macfont_set_family_cache (symbol, result);
1059       CFRelease (pat_desc);
1060     }
1062   return result;
1065 #define WIDTH_FRAC_BITS         (4)
1066 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1068 struct macfont_metrics
1070   unsigned char lbearing_low, rbearing_low;
1071   signed lbearing_high : 4, rbearing_high : 4;
1072   unsigned char ascent_low, descent_low;
1073   signed ascent_high : 4, descent_high : 4;
1075   /* These two members are used for fixed-point representation of
1076      glyph width.  The `width_int' member is an integer that is
1077      closest to the width.  The `width_frac' member is the fractional
1078      adjustment representing a value in [-.5, .5], multiplied by
1079      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1080      the advance delta for centering instead of the glyph width.  */
1081   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1084 #define METRICS_VALUE(metrics, member)                          \
1085   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1086 #define METRICS_SET_VALUE(metrics, member, value)                   \
1087   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
1088     (metrics)->member##_high = tmp >> 8;} while (0)
1090 enum metrics_status
1092   METRICS_INVALID = -1,    /* metrics entry is invalid */
1093   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1096 #define METRICS_STATUS(metrics)                                         \
1097   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1098 #define METRICS_SET_STATUS(metrics, status)                     \
1099   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1100     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1102 #define METRICS_NCOLS_PER_ROW   (128)
1103 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1104 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1106 static int
1107 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1108                        struct font_metrics *metrics, CGFloat *advance_delta,
1109                        int force_integral_p)
1111   struct macfont_info *macfont_info = (struct macfont_info *) font;
1112   CTFontRef macfont = macfont_info->macfont;
1113   int row, col;
1114   struct macfont_metrics *cache;
1115   int width;
1117   row = glyph / METRICS_NCOLS_PER_ROW;
1118   col = glyph % METRICS_NCOLS_PER_ROW;
1119   if (row >= macfont_info->metrics_nrows)
1120     {
1121       macfont_info->metrics =
1122         xrealloc (macfont_info->metrics,
1123                   sizeof (struct macfont_metrics *) * (row + 1));
1124       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1125               (sizeof (struct macfont_metrics *)
1126                * (row + 1 - macfont_info->metrics_nrows)));
1127       macfont_info->metrics_nrows = row + 1;
1128     }
1129   if (macfont_info->metrics[row] == NULL)
1130     {
1131       struct macfont_metrics *new;
1132       int i;
1134       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1135       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1136         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1137       macfont_info->metrics[row] = new;
1138     }
1139   cache = macfont_info->metrics[row] + col;
1141   if (METRICS_STATUS (cache) == METRICS_INVALID)
1142     {
1143       CGFloat fwidth;
1145       if (macfont_info->screen_font)
1146         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1147       else
1148         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1150       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1151          advance delta value.  */
1152       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1153         fwidth = (font->pixel_size - fwidth) / 2;
1154       cache->width_int = lround (fwidth);
1155       cache->width_frac = lround ((fwidth - cache->width_int)
1156                                   * WIDTH_FRAC_SCALE);
1157       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1158     }
1159   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1160     width = font->pixel_size;
1161   else
1162     width = cache->width_int;
1164   if (metrics)
1165     {
1166       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1167         {
1168           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1170           if (macfont_info->synthetic_italic_p)
1171             {
1172               /* We assume the members a, b, c, and d in
1173                  synthetic_italic_atfm are non-negative.  */
1174               bounds.origin =
1175                 CGPointApplyAffineTransform (bounds.origin,
1176                                              synthetic_italic_atfm);
1177               bounds.size =
1178                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1179             }
1180           if (macfont_info->synthetic_bold_p && ! force_integral_p)
1181             {
1182               CGFloat d = - synthetic_bold_factor * CTFontGetSize (macfont) / 2;
1184               bounds = CGRectInset (bounds, d, d);
1185             }
1186           switch (macfont_info->spacing)
1187             {
1188             case MACFONT_SPACING_PROPORTIONAL:
1189               bounds.origin.x += - (cache->width_frac
1190                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1191               break;
1192             case MACFONT_SPACING_MONO:
1193               break;
1194             case MACFONT_SPACING_SYNTHETIC_MONO:
1195               bounds.origin.x += (cache->width_int
1196                                   + (cache->width_frac
1197                                      / (CGFloat) WIDTH_FRAC_SCALE));
1198               break;
1199             }
1200           if (bounds.size.width > 0)
1201             {
1202               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1203               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1204                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1205             }
1206           bounds = CGRectIntegral (bounds);
1207           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1208           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1209           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1210           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1211         }
1212       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1213       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1214       metrics->width = width;
1215       metrics->ascent = METRICS_VALUE (cache, ascent);
1216       metrics->descent = METRICS_VALUE (cache, descent);
1217     }
1219   if (advance_delta)
1220     {
1221       switch (macfont_info->spacing)
1222         {
1223         case MACFONT_SPACING_PROPORTIONAL:
1224           *advance_delta = (force_integral_p ? 0
1225                             : - (cache->width_frac
1226                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1227           break;
1228         case MACFONT_SPACING_MONO:
1229           *advance_delta = 0;
1230           break;
1231         case MACFONT_SPACING_SYNTHETIC_MONO:
1232           *advance_delta = (force_integral_p ? cache->width_int
1233                             : (cache->width_int
1234                                + (cache->width_frac
1235                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1236           break;
1237         }
1238     }
1240   return width;
1243 static CFMutableDictionaryRef macfont_cache_dictionary;
1245 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1246    equal to the number of rows that are invalid as BMP (i.e., from
1247    U+D800 to U+DFFF).  */
1248 #define ROW_PERM_OFFSET (8)
1250 /* The number of glyphs that can be stored in a value for a single
1251    entry of CFDictionary.  */
1252 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1254 struct macfont_cache
1256   int reference_count;
1257   CFCharacterSetRef cf_charset;
1258   struct {
1259     /* The cached glyph for a BMP character c is stored in
1260        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1261        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1262     unsigned char row_nkeys_or_perm[256];
1263     CGGlyph **matrix;
1265     /* Number of rows for which the BMP cache is allocated so far.
1266        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1267     int nrows;
1269     /* The cached glyph for a character c is stored as the (c %
1270        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1271        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1272        not stored here if row_nkeys_or_perm[c / 256] >=
1273        ROW_PERM_OFFSET.  */
1274     CFMutableDictionaryRef dictionary;
1275   } glyph;
1277   struct {
1278     /* UVS (Unicode Variation Sequence) subtable data, which is of
1279        type CFDataRef if available.  NULL means it is not initialized
1280        yet.  kCFNull means the subtable is not found and there is no
1281        suitable fallback table for this font.  */
1282     CFTypeRef table;
1284     /* Character collection specifying the destination of the mapping
1285        provided by `table' above.  If `table' is obtained from the UVS
1286        subtable in the font cmap table, then the value of this member
1287        should be kCTCharacterCollectionIdentityMapping.  */
1288     CTCharacterCollection collection;
1289   } uvs;
1292 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1293 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1294 static void macfont_release_cache (struct macfont_cache *);
1295 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1296 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1297 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1298 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1299                                           CTCharacterCollection, CGFontIndex);
1300 static CFDataRef macfont_get_uvs_table (struct font *, CTCharacterCollection *);
1302 static struct macfont_cache *
1303 macfont_lookup_cache (CFStringRef key)
1305   struct macfont_cache *cache;
1307   if (macfont_cache_dictionary == NULL)
1308     {
1309       macfont_cache_dictionary =
1310         CFDictionaryCreateMutable (NULL, 0,
1311                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1312       cache = NULL;
1313     }
1314   else
1315     cache = ((struct macfont_cache *)
1316              CFDictionaryGetValue (macfont_cache_dictionary, key));
1318   if (cache == NULL)
1319     {
1320       CTFontRef macfont = CTFontCreateWithName (key, 0, NULL);
1322       if (macfont)
1323         {
1324           cache = xzalloc (sizeof (struct macfont_cache));
1325           /* Treat the LastResort font as if it contained glyphs for
1326              all characters.  This may look too rough, but neither
1327              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1328              for this font is correct for non-BMP characters on Mac OS
1329              X 10.5, anyway.  */
1330           if (CFEqual (key, CFSTR ("LastResort")))
1331             {
1332               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1334               cache->cf_charset =
1335                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1336             }
1337           if (cache->cf_charset == NULL)
1338             cache->cf_charset = CTFontCopyCharacterSet (macfont);
1339           CFDictionaryAddValue (macfont_cache_dictionary, key,
1340                                 (const void *) cache);
1341           CFRelease (macfont);
1342         }
1343     }
1345   return cache;
1348 static struct macfont_cache *
1349 macfont_retain_cache (struct macfont_cache *cache)
1351   cache->reference_count++;
1353   return cache;
1356 static void
1357 macfont_release_cache (struct macfont_cache *cache)
1359   if (--cache->reference_count == 0)
1360     {
1361       int i;
1363       for (i = 0; i < cache->glyph.nrows; i++)
1364         xfree (cache->glyph.matrix[i]);
1365       xfree (cache->glyph.matrix);
1366       if (cache->glyph.dictionary)
1367         CFRelease (cache->glyph.dictionary);
1368       memset (&cache->glyph, 0, sizeof (cache->glyph));
1369       if (cache->uvs.table)
1370         CFRelease (cache->uvs.table);
1371       memset (&cache->uvs, 0, sizeof (cache->uvs));
1372     }
1375 static CFCharacterSetRef
1376 macfont_get_cf_charset (struct font *font)
1378   struct macfont_info *macfont_info = (struct macfont_info *) font;
1380   return macfont_info->cache->cf_charset;
1383 static CFCharacterSetRef
1384 macfont_get_cf_charset_for_name (CFStringRef name)
1386   struct macfont_cache *cache = macfont_lookup_cache (name);
1388   return cache->cf_charset;
1391 static CGGlyph
1392 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1394   struct macfont_info *macfont_info = (struct macfont_info *) font;
1395   CTFontRef macfont = macfont_info->macfont;
1396   struct macfont_cache *cache = macfont_info->cache;
1398   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1399     {
1400       int row = c / 256;
1401       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1403       if (nkeys_or_perm < ROW_PERM_OFFSET)
1404         {
1405           UniChar unichars[256], ch;
1406           CGGlyph *glyphs;
1407           int i, len;
1408           int nrows;
1409           dispatch_queue_t queue;
1410           dispatch_group_t group = NULL;
1412           if (row != 0)
1413             {
1414               CFMutableDictionaryRef dictionary;
1415               uintptr_t key, value;
1416               int nshifts;
1417               CGGlyph glyph;
1419               if (cache->glyph.dictionary == NULL)
1420                 cache->glyph.dictionary =
1421                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1422               dictionary = cache->glyph.dictionary;
1423               key = c / NGLYPHS_IN_VALUE;
1424               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1425               value = ((uintptr_t)
1426                        CFDictionaryGetValue (dictionary, (const void *) key));
1427               glyph = (value >> nshifts);
1428               if (glyph)
1429                 return glyph;
1431               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1432                 {
1433                   ch = c;
1434                   if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1435                       || glyph == 0)
1436                     glyph = kCGFontIndexInvalid;
1438                   if (value == 0)
1439                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1440                   value |= ((uintptr_t) glyph << nshifts);
1441                   CFDictionarySetValue (dictionary, (const void *) key,
1442                                         (const void *) value);
1444                   return glyph;
1445                 }
1447               queue =
1448                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1449               group = dispatch_group_create ();
1450               dispatch_group_async (group, queue, ^{
1451                   int nkeys;
1452                   uintptr_t key;
1453                   nkeys = nkeys_or_perm;
1454                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1455                     if (CFDictionaryContainsKey (dictionary,
1456                                                  (const void *) key))
1457                       {
1458                         CFDictionaryRemoveValue (dictionary,
1459                                                  (const void *) key);
1460                         if (--nkeys == 0)
1461                           break;
1462                       }
1463                 });
1464             }
1466           len = 0;
1467           for (i = 0; i < 256; i++)
1468             {
1469               ch = row * 256 + i;
1470               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1471                 unichars[len++] = ch;
1472             }
1474           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1475           if (len > 0)
1476             {
1477               CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1478               while (i > len)
1479                 {
1480                   int next = unichars[len - 1] % 256;
1482                   while (--i > next)
1483                     glyphs[i] = kCGFontIndexInvalid;
1485                   len--;
1486                   glyphs[i] = glyphs[len];
1487                   if (len == 0)
1488                     break;
1489                 }
1490             }
1491           if (i > len)
1492             while (i-- > 0)
1493               glyphs[i] = kCGFontIndexInvalid;
1495           nrows = cache->glyph.nrows;
1496           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1497           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1498           nrows++;
1499           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1500                                           sizeof (CGGlyph *) * nrows);
1501           cache->glyph.matrix[nrows - 1] = glyphs;
1502           cache->glyph.nrows = nrows;
1504           if (group)
1505             {
1506               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1507               dispatch_release (group);
1508             }
1509         }
1511       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1512     }
1513   else
1514     {
1515       uintptr_t key, value;
1516       int nshifts;
1517       CGGlyph glyph;
1519       if (cache->glyph.dictionary == NULL)
1520         cache->glyph.dictionary =
1521           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1522       key = c / NGLYPHS_IN_VALUE;
1523       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1524       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1525                                                 (const void *) key);
1526       glyph = (value >> nshifts);
1527       if (glyph == 0)
1528         {
1529           UniChar unichars[2];
1530           CGGlyph glyphs[2];
1531           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1533           if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1534             glyph = glyphs[0];
1535           if (glyph == 0)
1536             glyph = kCGFontIndexInvalid;
1538           value |= ((uintptr_t) glyph << nshifts);
1539           CFDictionarySetValue (cache->glyph.dictionary,
1540                                 (const void *) key, (const void *) value);
1541         }
1543       return glyph;
1544     }
1547 static CGGlyph
1548 macfont_get_glyph_for_cid (struct font *font, CTCharacterCollection collection,
1549                            CGFontIndex cid)
1551   struct macfont_info *macfont_info = (struct macfont_info *) font;
1552   CTFontRef macfont = macfont_info->macfont;
1554   /* Cache it? */
1555   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1558 static CFDataRef
1559 macfont_get_uvs_table (struct font *font, CTCharacterCollection *collection)
1561   struct macfont_info *macfont_info = (struct macfont_info *) font;
1562   CTFontRef macfont = macfont_info->macfont;
1563   struct macfont_cache *cache = macfont_info->cache;
1564   CFDataRef result = NULL;
1566   if (cache->uvs.table == NULL)
1567     {
1568       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1569       CTCharacterCollection uvs_collection =
1570         kCTCharacterCollectionIdentityMapping;
1572       if (uvs_table == NULL
1573           && mac_font_get_glyph_for_cid (macfont,
1574                                          kCTCharacterCollectionAdobeJapan1,
1575                                          6480) != kCGFontIndexInvalid)
1576         {
1577           /* If the glyph for U+4E55 is accessible via its CID 6480,
1578              then we use the Adobe-Japan1 UVS table, which maps a
1579              variation sequence to a CID, as a fallback.  */
1580           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1582           if (mac_uvs_table_adobe_japan1 == NULL)
1583             mac_uvs_table_adobe_japan1 =
1584               CFDataCreateWithBytesNoCopy (NULL,
1585                                            mac_uvs_table_adobe_japan1_bytes,
1586                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1587                                            kCFAllocatorNull);
1588           if (mac_uvs_table_adobe_japan1)
1589             {
1590               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1591               uvs_collection = kCTCharacterCollectionAdobeJapan1;
1592             }
1593         }
1594       if (uvs_table == NULL)
1595         cache->uvs.table = kCFNull;
1596       else
1597         cache->uvs.table = uvs_table;
1598       cache->uvs.collection = uvs_collection;
1599     }
1601   if (cache->uvs.table != kCFNull)
1602     {
1603       result = cache->uvs.table;
1604       *collection = cache->uvs.collection;
1605     }
1607   return result;
1610 static Lisp_Object macfont_get_cache (struct frame *);
1611 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1612 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1613 static Lisp_Object macfont_list_family (struct frame *);
1614 static void macfont_free_entity (Lisp_Object);
1615 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1616 static void macfont_close (struct font *);
1617 static int macfont_has_char (Lisp_Object, int);
1618 static unsigned macfont_encode_char (struct font *, int);
1619 static void macfont_text_extents (struct font *, unsigned int *, int,
1620                                   struct font_metrics *);
1621 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1622 static Lisp_Object macfont_shape (Lisp_Object);
1623 static int macfont_variation_glyphs (struct font *, int c,
1624                                      unsigned variations[256]);
1625 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1627 static struct font_driver macfont_driver =
1628   {
1629     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1630     0,                          /* case insensitive */
1631     macfont_get_cache,
1632     macfont_list,
1633     macfont_match,
1634     macfont_list_family,
1635     macfont_free_entity,
1636     macfont_open,
1637     macfont_close,
1638     NULL,                       /* prepare_face */
1639     NULL,                       /* done_face */
1640     macfont_has_char,
1641     macfont_encode_char,
1642     macfont_text_extents,
1643     macfont_draw,
1644     NULL,                       /* get_bitmap */
1645     NULL,                       /* free_bitmap */
1646     NULL,                       /* anchor_point */
1647     NULL,                       /* otf_capability */
1648     NULL,                       /* otf_drive */
1649     NULL,                       /* start_for_frame */
1650     NULL,                       /* end_for_frame */
1651     macfont_shape,
1652     NULL,                       /* check */
1653     macfont_variation_glyphs,
1654     macfont_filter_properties,
1655   };
1657 static Lisp_Object
1658 macfont_get_cache (struct frame * f)
1660   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1662   return (dpyinfo->name_list_element);
1665 static int
1666 macfont_get_charset (Lisp_Object registry)
1668   char *str = SSDATA (SYMBOL_NAME (registry));
1669   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1670   Lisp_Object regexp;
1671   int i, j;
1673   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1674     {
1675       if (str[i] == '.')
1676         re[j++] = '\\';
1677       else if (str[i] == '*')
1678         re[j++] = '.';
1679       re[j] = str[i];
1680       if (re[j] == '?')
1681         re[j] = '.';
1682     }
1683   re[j] = '\0';
1684   regexp = make_unibyte_string (re, j);
1685   for (i = 0; cf_charset_table[i].name; i++)
1686     if (fast_c_string_match_ignore_case
1687         (regexp, cf_charset_table[i].name,
1688          strlen (cf_charset_table[i].name)) >= 0)
1689       break;
1690   if (! cf_charset_table[i].name)
1691     return -1;
1692   if (! cf_charset_table[i].cf_charset)
1693     {
1694       int *uniquifier = cf_charset_table[i].uniquifier;
1695       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1696       CFIndex count = 0;
1697       CFStringRef string;
1698       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1700       if (! charset)
1701         return -1;
1702       for (j = 0; uniquifier[j]; j++)
1703         {
1704           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1705                                                         unichars + count);
1706           CFCharacterSetAddCharactersInRange (charset,
1707                                               CFRangeMake (uniquifier[j], 1));
1708         }
1710       string = CFStringCreateWithCharacters (NULL, unichars, count);
1711       if (! string)
1712         {
1713           CFRelease (charset);
1714           return -1;
1715         }
1716       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1717                                                                  charset);
1718       CFRelease (charset);
1719       /* CFCharacterSetCreateWithCharactersInString does not handle
1720          surrogate pairs properly as of Mac OS X 10.5.  */
1721       cf_charset_table[i].cf_charset_string = string;
1722     }
1723   return i;
1726 struct OpenTypeSpec
1728   Lisp_Object script;
1729   unsigned int script_tag, langsys_tag;
1730   int nfeatures[2];
1731   unsigned int *features[2];
1734 #define OTF_SYM_TAG(SYM, TAG)                               \
1735   do {                                                      \
1736     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1737     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1738   } while (0)
1740 #define OTF_TAG_STR(TAG, P)                     \
1741   do {                                          \
1742     (P)[0] = (char) (TAG >> 24);                \
1743     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1744     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1745     (P)[3] = (char) (TAG & 0xFF);               \
1746     (P)[4] = '\0';                              \
1747   } while (0)
1749 static struct OpenTypeSpec *
1750 macfont_get_open_type_spec (Lisp_Object otf_spec)
1752   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1753   Lisp_Object val;
1754   int i, j;
1755   bool negative;
1757   if (! spec)
1758     return NULL;
1759   spec->script = XCAR (otf_spec);
1760   if (! NILP (spec->script))
1761     {
1762       OTF_SYM_TAG (spec->script, spec->script_tag);
1763       val = assq_no_quit (spec->script, Votf_script_alist);
1764       if (CONSP (val) && SYMBOLP (XCDR (val)))
1765         spec->script = XCDR (val);
1766       else
1767         spec->script = Qnil;
1768     }
1769   else
1770     spec->script_tag = 0x44464C54;      /* "DFLT" */
1771   otf_spec = XCDR (otf_spec);
1772   spec->langsys_tag = 0;
1773   if (! NILP (otf_spec))
1774     {
1775       val = XCAR (otf_spec);
1776       if (! NILP (val))
1777         OTF_SYM_TAG (val, spec->langsys_tag);
1778       otf_spec = XCDR (otf_spec);
1779     }
1780   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1781   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1782     {
1783       Lisp_Object len;
1785       val = XCAR (otf_spec);
1786       if (NILP (val))
1787         continue;
1788       len = Flength (val);
1789       spec->features[i] =
1790         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1791          ? 0
1792          : malloc (XINT (len) * sizeof *spec->features[i]));
1793       if (! spec->features[i])
1794         {
1795           if (i > 0 && spec->features[0])
1796             free (spec->features[0]);
1797           free (spec);
1798           return NULL;
1799         }
1800       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1801         {
1802           if (NILP (XCAR (val)))
1803             negative = 1;
1804           else
1805             {
1806               unsigned int tag;
1808               OTF_SYM_TAG (XCAR (val), tag);
1809               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1810             }
1811         }
1812       spec->nfeatures[i] = j;
1813     }
1814   return spec;
1817 static CFMutableDictionaryRef
1818 macfont_create_attributes_with_spec (Lisp_Object spec)
1820   Lisp_Object tmp, extra;
1821   CFMutableArrayRef langarray = NULL;
1822   CFCharacterSetRef charset = NULL;
1823   CFStringRef charset_string = NULL;
1824   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1825   Lisp_Object script = Qnil;
1826   Lisp_Object registry;
1827   int cf_charset_idx, i;
1828   struct OpenTypeSpec *otspec = NULL;
1829   struct {
1830     enum font_property_index index;
1831     CFStringRef trait;
1832     CGPoint points[6];
1833   } numeric_traits[] =
1834       {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1835         {{-0.4, 50},            /* light */
1836          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1837          {0, 100},              /* normal */
1838          {0.24, 140},           /* (semi-bold + normal) / 2 */
1839          {0.4, 200},            /* bold */
1840          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1841        {FONT_SLANT_INDEX, kCTFontSlantTrait,
1842         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1843        {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1844         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1846   registry = AREF (spec, FONT_REGISTRY_INDEX);
1847   if (NILP (registry)
1848       || EQ (registry, Qascii_0)
1849       || EQ (registry, Qiso10646_1)
1850       || EQ (registry, Qunicode_bmp))
1851     cf_charset_idx = -1;
1852   else
1853     {
1854       CFStringRef lang;
1856       cf_charset_idx = macfont_get_charset (registry);
1857       if (cf_charset_idx < 0)
1858         goto err;
1859       charset = cf_charset_table[cf_charset_idx].cf_charset;
1860       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1861       lang = cf_charset_table[cf_charset_idx].lang;
1862       if (lang)
1863         {
1864           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1865           if (! langarray)
1866             goto err;
1867           CFArrayAppendValue (langarray, lang);
1868         }
1869     }
1871   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1872        CONSP (extra); extra = XCDR (extra))
1873     {
1874       Lisp_Object key, val;
1876       tmp = XCAR (extra);
1877       key = XCAR (tmp), val = XCDR (tmp);
1878       if (EQ (key, QClang))
1879         {
1880           if (! langarray)
1881             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1882           if (! langarray)
1883             goto err;
1884           if (SYMBOLP (val))
1885             val = list1 (val);
1886           for (; CONSP (val); val = XCDR (val))
1887             if (SYMBOLP (XCAR (val)))
1888               {
1889                 CFStringRef lang =
1890                   cfstring_create_with_string_noencode (SYMBOL_NAME
1891                                                         (XCAR (val)));
1893                 if (lang == NULL)
1894                   goto err;
1895                 CFArrayAppendValue (langarray, lang);
1896                 CFRelease (lang);
1897               }
1898         }
1899       else if (EQ (key, QCotf))
1900         {
1901           otspec = macfont_get_open_type_spec (val);
1902           if (! otspec)
1903             goto err;
1904           script = otspec->script;
1905         }
1906       else if (EQ (key, QCscript))
1907         script = val;
1908     }
1910   if (! NILP (script) && ! charset)
1911     {
1912       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1914       if (CONSP (chars) && CONSP (CDR (chars)))
1915         {
1916           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1917           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1919           if (! string || !cs)
1920             {
1921               if (string)
1922                 CFRelease (string);
1923               else if (cs)
1924                 CFRelease (cs);
1925               goto err;
1926             }
1927           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1928             if (CHARACTERP (XCAR (chars)))
1929               {
1930                 UniChar unichars[2];
1931                 CFIndex count =
1932                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1933                                                        unichars);
1934                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1936                 CFStringAppendCharacters (string, unichars, count);
1937                 CFCharacterSetAddCharactersInRange (cs, range);
1938               }
1939           charset = cs;
1940           /* CFCharacterSetCreateWithCharactersInString does not
1941              handle surrogate pairs properly as of Mac OS X 10.5.  */
1942           charset_string = string;
1943         }
1944     }
1946   attributes = CFDictionaryCreateMutable (NULL, 0,
1947                                           &kCFTypeDictionaryKeyCallBacks,
1948                                           &kCFTypeDictionaryValueCallBacks);
1949   if (! attributes)
1950     goto err;
1952   tmp = AREF (spec, FONT_FAMILY_INDEX);
1953   if (SYMBOLP (tmp) && ! NILP (tmp))
1954     {
1955       CFStringRef family = macfont_create_family_with_symbol (tmp);
1957       if (! family)
1958         goto err;
1959       CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
1960                             family);
1961       CFRelease (family);
1962     }
1964   traits = CFDictionaryCreateMutable (NULL, 4,
1965                                       &kCFTypeDictionaryKeyCallBacks,
1966                                       &kCFTypeDictionaryValueCallBacks);
1967   if (! traits)
1968     goto err;
1970   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1971     {
1972       tmp = AREF (spec, numeric_traits[i].index);
1973       if (INTEGERP (tmp))
1974         {
1975           CGPoint *point = numeric_traits[i].points;
1976           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1977           CFNumberRef num;
1979           while (point->y < floatval)
1980             point++;
1981           if (point == numeric_traits[i].points)
1982             point++;
1983           else if (point->y == CGFLOAT_MAX)
1984             point--;
1985           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1986                                        * ((point->x - (point - 1)->x)
1987                                           / (point->y - (point - 1)->y)));
1988           if (floatval > 1.0)
1989             floatval = 1.0;
1990           else if (floatval < -1.0)
1991             floatval = -1.0;
1992           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1993           if (! num)
1994             goto err;
1995           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1996           CFRelease (num);
1997         }
1998     }
1999   if (CFDictionaryGetCount (traits))
2000     CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2002   if (charset)
2003     CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2004                           charset);
2005   if (charset_string)
2006     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2007                           charset_string);
2008   if (langarray)
2009     CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2011   goto finish;
2013  err:
2014   if (attributes)
2015     {
2016       CFRelease (attributes);
2017       attributes = NULL;
2018     }
2020  finish:
2021   if (langarray) CFRelease (langarray);
2022   if (charset && cf_charset_idx < 0) CFRelease (charset);
2023   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2024   if (traits) CFRelease (traits);
2025   if (otspec)
2026     {
2027       if (otspec->nfeatures[0] > 0)
2028         free (otspec->features[0]);
2029       if (otspec->nfeatures[1] > 0)
2030         free (otspec->features[1]);
2031       free (otspec);
2032     }
2034   return attributes;
2037 static Boolean
2038 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2039                                           CFCharacterSetRef charset,
2040                                           Lisp_Object chars,
2041                                           CFArrayRef languages)
2043   Boolean result = true;
2045   if (charset || VECTORP (chars))
2046     {
2047       CFCharacterSetRef desc_charset =
2048         CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2050       if (desc_charset == NULL)
2051         result = false;
2052       else
2053         {
2054           if (charset)
2055             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2056           else                  /* VECTORP (chars) */
2057             {
2058               ptrdiff_t j;
2060               for (j = 0; j < ASIZE (chars); j++)
2061                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2062                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2063                                                             XFASTINT (AREF (chars, j))))
2064                   break;
2065               if (j == ASIZE (chars))
2066                 result = false;
2067             }
2068           CFRelease (desc_charset);
2069         }
2070     }
2071   if (result && languages)
2072     result = mac_font_descriptor_supports_languages (desc, languages);
2074   return result;
2077 static int
2078 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2079                          CTFontSymbolicTraits sym_traits2)
2081   CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2082   int distance = 0;
2084   /* We prefer synthetic bold of italic to synthetic italic of bold
2085      when both bold and italic are available but bold-italic is not
2086      available.  */
2087   if (diff & kCTFontTraitBold)
2088     distance |= (1 << 0);
2089   if (diff & kCTFontTraitItalic)
2090     distance |= (1 << 1);
2091   if (diff & kCTFontTraitMonoSpace)
2092     distance |= (1 << 2);
2094   return distance;
2097 static Boolean
2098 macfont_closest_traits_index_p (CFArrayRef traits_array,
2099                                 CTFontSymbolicTraits target,
2100                                 CFIndex index)
2102   CFIndex i, count = CFArrayGetCount (traits_array);
2103   CTFontSymbolicTraits traits;
2104   int my_distance;
2106   traits = ((CTFontSymbolicTraits) (uintptr_t)
2107             CFArrayGetValueAtIndex (traits_array, index));
2108   my_distance = macfont_traits_distance (target, traits);
2110   for (i = 0; i < count; i++)
2111     if (i != index)
2112       {
2113         traits = ((CTFontSymbolicTraits) (uintptr_t)
2114                   CFArrayGetValueAtIndex (traits_array, i));
2115         if (macfont_traits_distance (target, traits) < my_distance)
2116           return false;
2117       }
2119   return true;
2122 static Lisp_Object
2123 macfont_list (struct frame *f, Lisp_Object spec)
2125   Lisp_Object val = Qnil, family, extra;
2126   int i, n;
2127   CFStringRef family_name = NULL;
2128   CFMutableDictionaryRef attributes = NULL, traits;
2129   Lisp_Object chars = Qnil;
2130   int spacing = -1;
2131   CTFontSymbolicTraits synth_sym_traits = 0;
2132   CFArrayRef families;
2133   CFIndex families_count;
2134   CFCharacterSetRef charset = NULL;
2135   CFArrayRef languages = NULL;
2137   block_input ();
2139   family = AREF (spec, FONT_FAMILY_INDEX);
2140   if (! NILP (family))
2141     {
2142       family_name = macfont_create_family_with_symbol (family);
2143       if (family_name == NULL)
2144         goto finish;
2145     }
2147   attributes = macfont_create_attributes_with_spec (spec);
2148   if (! attributes)
2149     goto finish;
2151   languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2153   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2154     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2156   traits = ((CFMutableDictionaryRef)
2157             CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2159   n = FONT_SLANT_NUMERIC (spec);
2160   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2161     {
2162       synth_sym_traits |= kCTFontTraitItalic;
2163       if (traits)
2164         CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2165     }
2167   n = FONT_WEIGHT_NUMERIC (spec);
2168   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2169     {
2170       synth_sym_traits |= kCTFontTraitBold;
2171       if (traits)
2172         CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2173     }
2175   if (languages
2176       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2177     {
2178       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2180       if (CFStringHasPrefix (language, CFSTR ("ja"))
2181           || CFStringHasPrefix (language, CFSTR ("ko"))
2182           || CFStringHasPrefix (language, CFSTR ("zh")))
2183         synth_sym_traits |= kCTFontTraitMonoSpace;
2184     }
2186   /* Create array of families.  */
2187   if (family_name)
2188     families = CFArrayCreate (NULL, (const void **) &family_name,
2189                               1, &kCFTypeArrayCallBacks);
2190   else
2191     {
2192       CFStringRef pref_family;
2193       CFIndex families_count, pref_family_index = -1;
2195       families = macfont_copy_available_families_cache ();
2196       if (families == NULL)
2197         goto err;
2199       families_count = CFArrayGetCount (families);
2201       /* Move preferred family to the front if exists.  */
2202       pref_family =
2203         mac_font_create_preferred_family_for_attributes (attributes);
2204       if (pref_family)
2205         {
2206           pref_family_index =
2207             CFArrayGetFirstIndexOfValue (families,
2208                                          CFRangeMake (0, families_count),
2209                                          pref_family);
2210           CFRelease (pref_family);
2211         }
2212       if (pref_family_index > 0)
2213         {
2214           CFMutableArrayRef mutable_families =
2215             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2217           if (mutable_families)
2218             {
2219               CFArrayAppendValue (mutable_families,
2220                                   CFArrayGetValueAtIndex (families,
2221                                                           pref_family_index));
2222               CFArrayAppendArray (mutable_families, families,
2223                                   CFRangeMake (0, pref_family_index));
2224               if (pref_family_index + 1 < families_count)
2225                 CFArrayAppendArray (mutable_families, families,
2226                                     CFRangeMake (pref_family_index + 1,
2227                                                  families_count
2228                                                  - (pref_family_index + 1)));
2229               CFRelease (families);
2230               families = mutable_families;
2231             }
2232         }
2233     }
2235   charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2236   if (charset)
2237     {
2238       CFRetain (charset);
2239       CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2240     }
2241   else
2242     {
2243       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2244       if (! NILP (val))
2245         {
2246           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2247           if (CONSP (val) && VECTORP (XCDR (val)))
2248             chars = XCDR (val);
2249         }
2250       val = Qnil;
2251     }
2253   if (languages)
2254     {
2255       CFRetain (languages);
2256       CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2257     }
2259   val = Qnil;
2260   extra = AREF (spec, FONT_EXTRA_INDEX);
2261   families_count = CFArrayGetCount (families);
2262   for (i = 0; i < families_count; i++)
2263     {
2264       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2265       CTFontDescriptorRef pat_desc;
2266       CFArrayRef descs;
2267       CFIndex descs_count;
2268       CFMutableArrayRef filtered_descs, traits_array;
2269       Lisp_Object entity;
2270       int j;
2272       CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2273                             family_name);
2274       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2275       if (! pat_desc)
2276         goto err;
2278       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2279          10.7 returns NULL if pat_desc represents the LastResort font.
2280          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2281          trailing "s") for such a font.  */
2282       if (!CFEqual (family_name, CFSTR ("LastResort")))
2283         descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2284       else
2285         {
2286           CTFontDescriptorRef lr_desc =
2287             CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2288           if (lr_desc)
2289             {
2290               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2291                                      &kCFTypeArrayCallBacks);
2292               CFRelease (lr_desc);
2293             }
2294           else
2295             descs = NULL;
2296         }
2297       CFRelease (pat_desc);
2298       if (! descs)
2299         continue;
2301       descs_count = CFArrayGetCount (descs);
2302       if (descs_count == 0
2303           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2304                                                         charset, chars,
2305                                                         languages))
2306         {
2307           CFRelease (descs);
2308           continue;
2309         }
2311       filtered_descs =
2312         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2313       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2314       for (j = 0; j < descs_count; j++)
2315         {
2316           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2317           CFDictionaryRef dict;
2318           CFNumberRef num;
2319           CTFontSymbolicTraits sym_traits;
2321           dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2322           if (dict == NULL)
2323             continue;
2325           num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2326           CFRelease (dict);
2327           if (num == NULL
2328               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2329             continue;
2331           if (spacing >= 0
2332               && !(synth_sym_traits & kCTFontTraitMonoSpace)
2333               && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2334                   != (spacing >= FONT_SPACING_MONO)))
2335             continue;
2337           /* Don't use a color bitmap font unless its family is
2338              explicitly specified.  */
2339           if ((sym_traits & kCTFontTraitColorGlyphs) && NILP (family))
2340             continue;
2342           if (j > 0
2343               && !macfont_supports_charset_and_languages_p (desc, charset,
2344                                                             chars, languages))
2345             continue;
2347           CFArrayAppendValue (filtered_descs, desc);
2348           CFArrayAppendValue (traits_array,
2349                               (const void *) (uintptr_t) sym_traits);
2350         }
2352       CFRelease (descs);
2353       descs = filtered_descs;
2354       descs_count = CFArrayGetCount (descs);
2356       for (j = 0; j < descs_count; j++)
2357         {
2358           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2359           CTFontSymbolicTraits sym_traits =
2360             ((CTFontSymbolicTraits) (uintptr_t)
2361              CFArrayGetValueAtIndex (traits_array, j));
2362           CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2364           mask_min = ((synth_sym_traits ^ sym_traits)
2365                       & (kCTFontTraitItalic | kCTFontTraitBold));
2366           if (FONT_SLANT_NUMERIC (spec) < 0)
2367             mask_min &= ~kCTFontTraitItalic;
2368           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2369             mask_min &= ~kCTFontTraitBold;
2371           mask_max = (synth_sym_traits & ~sym_traits);
2372           /* Synthetic bold does not work for bitmap-only fonts on Mac
2373              OS X 10.6.  */
2374           if ((mask_min ^ mask_max) & kCTFontTraitBold)
2375             {
2376               CFNumberRef format =
2377                 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2379               if (format)
2380                 {
2381                   uint32_t format_val;
2383                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2384                                         &format_val)
2385                       && format_val == kCTFontFormatBitmap)
2386                     mask_max &= ~kCTFontTraitBold;
2387                 }
2388             }
2389           if (spacing >= 0)
2390             mask_min |= (mask_max & kCTFontTraitMonoSpace);
2392           for (mmask = (mask_min & kCTFontTraitMonoSpace);
2393                mmask <= (mask_max & kCTFontTraitMonoSpace);
2394                mmask += kCTFontTraitMonoSpace)
2395             for (bmask = (mask_min & kCTFontTraitBold);
2396                  bmask <= (mask_max & kCTFontTraitBold);
2397                  bmask += kCTFontTraitBold)
2398               for (imask = (mask_min & kCTFontTraitItalic);
2399                    imask <= (mask_max & kCTFontTraitItalic);
2400                    imask += kCTFontTraitItalic)
2401                 {
2402                   CTFontSymbolicTraits synth = (imask | bmask | mmask);
2404                   if (synth == 0
2405                       || macfont_closest_traits_index_p (traits_array,
2406                                                          (sym_traits | synth),
2407                                                          j))
2408                     {
2409                       entity = macfont_descriptor_entity (desc, extra, synth);
2410                       if (! NILP (entity))
2411                         val = Fcons (entity, val);
2412                     }
2413                 }
2414         }
2416       CFRelease (traits_array);
2417       CFRelease (descs);
2418     }
2420   CFRelease (families);
2421   val = Fnreverse (val);
2422   goto finish;
2423  err:
2424   val = Qnil;
2426  finish:
2427   FONT_ADD_LOG ("macfont-list", spec, val);
2428   if (charset) CFRelease (charset);
2429   if (languages) CFRelease (languages);
2430   if (attributes) CFRelease (attributes);
2431   if (family_name) CFRelease (family_name);
2433   unblock_input ();
2435   return val;
2438 static Lisp_Object
2439 macfont_match (struct frame * frame, Lisp_Object spec)
2441   Lisp_Object entity = Qnil;
2442   CFMutableDictionaryRef attributes;
2443   CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2445   block_input ();
2447   attributes = macfont_create_attributes_with_spec (spec);
2448   if (attributes)
2449     {
2450       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2451       CFRelease (attributes);
2452     }
2453   if (pat_desc)
2454     {
2455       desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2456       CFRelease (pat_desc);
2457     }
2458   if (desc)
2459     {
2460       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2461                                           0);
2462       CFRelease (desc);
2463     }
2464   unblock_input ();
2466   FONT_ADD_LOG ("macfont-match", spec, entity);
2467   return entity;
2470 static Lisp_Object
2471 macfont_list_family (struct frame *frame)
2473   Lisp_Object list = Qnil;
2474   CFArrayRef families;
2476   block_input ();
2478   families = macfont_copy_available_families_cache ();
2479   if (families)
2480     {
2481       CFIndex i, count = CFArrayGetCount (families);
2483       for (i = 0; i < count; i++)
2484         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2485       CFRelease (families);
2486     }
2488   unblock_input ();
2490   return list;
2493 static void
2494 macfont_free_entity (Lisp_Object entity)
2496   Lisp_Object val = assq_no_quit (QCfont_entity,
2497                                   AREF (entity, FONT_EXTRA_INDEX));
2498   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2500   block_input ();
2501   CFRelease (name);
2502   unblock_input ();
2505 static Lisp_Object
2506 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2508   Lisp_Object val, font_object;
2509   CFStringRef font_name;
2510   struct macfont_info *macfont_info = NULL;
2511   struct font *font;
2512   int size;
2513   CTFontRef macfont;
2514   CTFontSymbolicTraits sym_traits;
2515   char name[256];
2516   int len, i, total_width;
2517   CGGlyph glyph;
2518   CGFloat ascent, descent, leading;
2520   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2521   if (! CONSP (val)
2522       || XTYPE (XCDR (val)) != Lisp_Misc
2523       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2524     return Qnil;
2525   font_name = XSAVE_POINTER (XCDR (val), 0);
2526   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2528   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2529   if (size == 0)
2530     size = pixel_size;
2532   block_input ();
2533   macfont = CTFontCreateWithName (font_name, size, NULL);
2534   if (macfont)
2535     {
2536       int fontsize = (int) [((NSFont *) macfont) pointSize];
2537       if (fontsize != size) size = fontsize;
2538     }
2539   unblock_input ();
2540   if (! macfont)
2541     return Qnil;
2543   font_object = font_build_object (VECSIZE (struct macfont_info),
2544                                    Qmac_ct, entity, size);
2545   font = XFONT_OBJECT (font_object);
2546   font->pixel_size = size;
2547   font->driver = &macfont_driver;
2548   font->encoding_charset = font->repertory_charset = -1;
2550   block_input ();
2552   macfont_info = (struct macfont_info *) font;
2553   macfont_info->macfont = macfont;
2554   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2556   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2557   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2558     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2559                                                                   size);
2560   else
2561     macfont_info->screen_font = NULL;
2562   macfont_info->cache = macfont_lookup_cache (font_name);
2563   macfont_retain_cache (macfont_info->cache);
2564   macfont_info->metrics = NULL;
2565   macfont_info->metrics_nrows = 0;
2566   macfont_info->synthetic_italic_p = 0;
2567   macfont_info->synthetic_bold_p = 0;
2568   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2569   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2570   if (!(sym_traits & kCTFontTraitItalic)
2571       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2572     macfont_info->synthetic_italic_p = 1;
2573   if (!(sym_traits & kCTFontTraitBold)
2574       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2575     macfont_info->synthetic_bold_p = 1;
2576   if (sym_traits & kCTFontTraitMonoSpace)
2577     macfont_info->spacing = MACFONT_SPACING_MONO;
2578   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2579            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2580                == FONT_SPACING_SYNTHETIC_MONO))
2581     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2582   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2583     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2584   else
2585     {
2586       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2587       if (CONSP (val))
2588         macfont_info->antialias =
2589           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2590     }
2591   macfont_info->color_bitmap_p = 0;
2592   if (sym_traits & kCTFontTraitColorGlyphs)
2593     macfont_info->color_bitmap_p = 1;
2595   glyph = macfont_get_glyph_for_character (font, ' ');
2596   if (glyph != kCGFontIndexInvalid)
2597     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2598   else
2599     /* dirty workaround */
2600     font->space_width = pixel_size;
2602   total_width = font->space_width;
2603   for (i = 1; i < 95; i++)
2604     {
2605       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2606       if (glyph == kCGFontIndexInvalid)
2607         break;
2608       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2609     }
2610   if (i == 95)
2611     font->average_width = total_width / 95;
2612   else
2613     font->average_width = font->space_width; /* XXX */
2615   if (!(macfont_info->screen_font
2616         && mac_screen_font_get_metrics (macfont_info->screen_font,
2617                                         &ascent, &descent, &leading)))
2618     {
2619       CFStringRef family_name;
2621       ascent = CTFontGetAscent (macfont);
2622       descent = CTFontGetDescent (macfont);
2623       leading = CTFontGetLeading (macfont);
2624       /* AppKit and WebKit do some adjustment to the heights of
2625          Courier, Helvetica, and Times.  */
2626       family_name = CTFontCopyFamilyName (macfont);
2627       if (family_name)
2628         {
2629           if (CFEqual (family_name, CFSTR ("Courier"))
2630               || CFEqual (family_name, CFSTR ("Helvetica"))
2631               || CFEqual (family_name, CFSTR ("Times")))
2632             ascent += (ascent + descent) * .15f;
2633           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2634             {
2635               leading *= .25f;
2636               ascent += leading;
2637             }
2638           CFRelease (family_name);
2639         }
2640     }
2641   font->ascent = ascent + 0.5f;
2642   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2643   if (CONSP (val) && !NILP (XCDR (val)))
2644     font->descent = descent + 0.5f;
2645   else
2646     font->descent = descent + leading + 0.5f;
2647   font->height = font->ascent + font->descent;
2649   font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2650   font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2652   unblock_input ();
2654   /* Unfortunately Xft doesn't provide a way to get minimum char
2655      width.  So, we use space_width instead.  */
2656   font->min_width = font->max_width = font->space_width; /* XXX */
2658   font->baseline_offset = 0;
2659   font->relative_compose = 0;
2660   font->default_ascent = 0;
2661   font->vertical_centering = 0;
2663   return font_object;
2666 static void
2667 macfont_close (struct font *font)
2669   struct macfont_info *macfont_info = (struct macfont_info *) font;
2671   if (macfont_info->cache)
2672     {
2673       int i;
2675       block_input ();
2676       CFRelease (macfont_info->macfont);
2677       CGFontRelease (macfont_info->cgfont);
2678       if (macfont_info->screen_font)
2679         CFRelease (macfont_info->screen_font);
2680       macfont_release_cache (macfont_info->cache);
2681       for (i = 0; i < macfont_info->metrics_nrows; i++)
2682         if (macfont_info->metrics[i])
2683           xfree (macfont_info->metrics[i]);
2684       if (macfont_info->metrics)
2685         xfree (macfont_info->metrics);
2686       macfont_info->cache = NULL;
2687       unblock_input ();
2688     }
2691 static int
2692 macfont_has_char (Lisp_Object font, int c)
2694   int result;
2695   CFCharacterSetRef charset;
2697   block_input ();
2698   if (FONT_ENTITY_P (font))
2699     {
2700       Lisp_Object val;
2701       CFStringRef name;
2703       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2704       val = XCDR (val);
2705       name = XSAVE_POINTER (val, 0);
2706       charset = macfont_get_cf_charset_for_name (name);
2707     }
2708   else
2709     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2711   result = CFCharacterSetIsLongCharacterMember (charset, c);
2712   unblock_input ();
2714   return result;
2717 static unsigned
2718 macfont_encode_char (struct font *font, int c)
2720   struct macfont_info *macfont_info = (struct macfont_info *) font;
2721   CGGlyph glyph;
2723   block_input ();
2724   glyph = macfont_get_glyph_for_character (font, c);
2725   unblock_input ();
2727   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2730 static void
2731 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2732                       struct font_metrics *metrics)
2734   int width, i;
2736   block_input ();
2737   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2738   for (i = 1; i < nglyphs; i++)
2739     {
2740       struct font_metrics m;
2741       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2742                                      NULL, 0);
2744       if (metrics)
2745         {
2746           if (width + m.lbearing < metrics->lbearing)
2747             metrics->lbearing = width + m.lbearing;
2748           if (width + m.rbearing > metrics->rbearing)
2749             metrics->rbearing = width + m.rbearing;
2750           if (m.ascent > metrics->ascent)
2751             metrics->ascent = m.ascent;
2752           if (m.descent > metrics->descent)
2753             metrics->descent = m.descent;
2754         }
2755       width += w;
2756     }
2757   unblock_input ();
2759   if (metrics)
2760     metrics->width = width;
2763 static int
2764 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2765               bool with_background)
2767   struct frame * f = s->f;
2768   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2769   CGRect background_rect;
2770   CGPoint text_position;
2771   CGGlyph *glyphs;
2772   CGPoint *positions;
2773   CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2774   bool no_antialias_p =
2775     (NILP (ns_antialias_text)
2776      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2777      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2778          && font_size <= macfont_antialias_threshold));
2779   int len = to - from;
2780   struct face *face = s->face;
2781   CGContextRef context;
2783   block_input ();
2785   if (with_background)
2786     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2787                                   s->width, FONT_HEIGHT (s->font));
2788   else
2789     background_rect = CGRectNull;
2791   text_position = CGPointMake (x, -y);
2792   glyphs = xmalloc (sizeof (CGGlyph) * len);
2793   {
2794     CGFloat advance_delta = 0;
2795     int i;
2796     CGFloat total_width = 0;
2798     positions = xmalloc (sizeof (CGPoint) * len);
2799     for (i = 0; i < len; i++)
2800       {
2801         int width;
2803         glyphs[i] = s->char2b[from + i];
2804         width = (s->padding_p ? 1
2805                  : macfont_glyph_extents (s->font, glyphs[i],
2806                                           NULL, &advance_delta,
2807                                           no_antialias_p));
2808         positions[i].x = total_width + advance_delta;
2809         positions[i].y = 0;
2810         total_width += width;
2811       }
2812   }
2814   context = [[NSGraphicsContext currentContext] graphicsPort];
2815   CGContextSaveGState (context);
2817   if (!CGRectIsNull (background_rect))
2818     {
2819       if (s->hl == DRAW_MOUSE_FACE)
2820         {
2821           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2822           if (!face)
2823             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2824         }
2825       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2826       CGContextFillRects (context, &background_rect, 1);
2827     }
2829   if (macfont_info->cgfont)
2830     {
2831       CGAffineTransform atfm;
2833       CGContextScaleCTM (context, 1, -1);
2834       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2835       if (macfont_info->synthetic_italic_p)
2836         atfm = synthetic_italic_atfm;
2837       else
2838         atfm = CGAffineTransformIdentity;
2839       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2840         {
2841           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2842           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2843           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2844         }
2845       if (no_antialias_p)
2846         CGContextSetShouldAntialias (context, false);
2848       CGContextSetTextMatrix (context, atfm);
2849       CGContextSetTextPosition (context, text_position.x, text_position.y);
2851 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2852       if (macfont_info->color_bitmap_p
2853 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2854           && CTFontDrawGlyphs != NULL
2855 #endif
2856           )
2857         {
2858           if (len > 0)
2859             {
2860               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2861                                 context);
2862             }
2863         }
2864       else
2865 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2866         {
2867           CGContextSetFont (context, macfont_info->cgfont);
2868           CGContextSetFontSize (context, font_size);
2869           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2870         }
2871     }
2874   xfree (glyphs);
2875   xfree (positions);
2876   CGContextRestoreGState (context);
2878   unblock_input ();
2880   return len;
2883 static Lisp_Object
2884 macfont_shape (Lisp_Object lgstring)
2886   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2887   struct macfont_info *macfont_info = (struct macfont_info *) font;
2888   CTFontRef macfont = macfont_info->macfont;
2889   ptrdiff_t glyph_len, len, i, j;
2890   CFIndex nonbmp_len;
2891   UniChar *unichars;
2892   CFIndex *nonbmp_indices;
2893   CFStringRef string;
2894   CFIndex used = 0;
2895   struct mac_glyph_layout *glyph_layouts;
2897   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2898   nonbmp_len = 0;
2899   for (i = 0; i < glyph_len; i++)
2900     {
2901       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2903       if (NILP (lglyph))
2904         break;
2905       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2906         nonbmp_len++;
2907     }
2909   len = i;
2911   if (INT_MAX / 2 < len)
2912     memory_full (SIZE_MAX);
2914   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2915   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2916   for (i = j = 0; i < len; i++)
2917     {
2918       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2920       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2921         {
2922           nonbmp_indices[j] = i + j;
2923           j++;
2924         }
2925     }
2926   nonbmp_indices[j] = len + j;  /* sentinel */
2928   block_input ();
2930   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2931                                                kCFAllocatorNull);
2932   if (string)
2933     {
2934       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2935       if (macfont_info->screen_font)
2936         used = mac_screen_font_shape (macfont_info->screen_font, string,
2937                                       glyph_layouts, glyph_len);
2938       else
2939         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2940       CFRelease (string);
2941     }
2943   unblock_input ();
2945   if (used == 0)
2946     return Qnil;
2948   block_input ();
2950   for (i = 0; i < used; i++)
2951     {
2952       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2953       struct mac_glyph_layout *gl = glyph_layouts + i;
2954       EMACS_INT from, to;
2955       struct font_metrics metrics;
2956       int xoff, yoff, wadjust;
2958       if (NILP (lglyph))
2959         {
2960           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2961           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2962         }
2964       from = gl->comp_range.location;
2965       /* Convert UTF-16 index to UTF-32.  */
2966       j = 0;
2967       while (nonbmp_indices[j] < from)
2968         j++;
2969       from -= j;
2970       LGLYPH_SET_FROM (lglyph, from);
2972       to = gl->comp_range.location + gl->comp_range.length;
2973       /* Convert UTF-16 index to UTF-32.  */
2974       while (nonbmp_indices[j] < to)
2975         j++;
2976       to -= j;
2977       LGLYPH_SET_TO (lglyph, to - 1);
2979       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2980          the composition is trivial.  */
2981       {
2982         UTF32Char c;
2984         if (unichars[gl->string_index] >= 0xD800
2985             && unichars[gl->string_index] < 0xDC00)
2986           c = (((unichars[gl->string_index] - 0xD800) << 10)
2987                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2988         else
2989           c = unichars[gl->string_index];
2990         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2991           c = 0;
2992         LGLYPH_SET_CHAR (lglyph, c);
2993       }
2995       {
2996         unsigned long cc = gl->glyph_id;
2997         LGLYPH_SET_CODE (lglyph, cc);
2998       }
3000       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3001       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3002       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3003       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3004       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3005       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3007       xoff = lround (gl->advance_delta);
3008       yoff = lround (- gl->baseline_delta);
3009       wadjust = lround (gl->advance);
3010       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3011         {
3012           Lisp_Object vec;
3014           vec = Fmake_vector (make_number (3), Qnil);
3015           ASET (vec, 0, make_number (xoff));
3016           ASET (vec, 1, make_number (yoff));
3017           ASET (vec, 2, make_number (wadjust));
3018           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3019         }
3020     }
3022   unblock_input ();
3024   return make_number (used);
3027 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3028 typedef UInt8 UINT24[3];
3030 #pragma pack(push, 1)
3031 struct variation_selector_record
3033   UINT24 var_selector;
3034   UInt32 default_uvs_offset, non_default_uvs_offset;
3036 struct uvs_table
3038   UInt16 format;
3039   UInt32 length, num_var_selector_records;
3040   struct variation_selector_record variation_selector_records[1];
3042 #define SIZEOF_UVS_TABLE_HEADER                                         \
3043   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3045 struct unicode_value_range
3047   UINT24 start_unicode_value;
3048   UInt8 additional_count;
3050 struct default_uvs_table {
3051   UInt32 num_unicode_value_ranges;
3052   struct unicode_value_range unicode_value_ranges[1];
3054 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3055   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3057 struct uvs_mapping
3059   UINT24 unicode_value;
3060   UInt16 glyph_id;
3062 struct non_default_uvs_table
3064   UInt32 num_uvs_mappings;
3065   struct uvs_mapping uvs_mappings[1];
3067 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3068   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3069 #pragma pack(pop)
3071 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3072 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3073    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3074    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3075 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3076 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3077 /* Succeeding one byte should also be accessible.  */
3078 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3079 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3081 /* Return UVS subtable for the specified FONT.  If the subtable is not
3082    found or ill-formatted, then return NULL.  */
3084 static CFDataRef
3085 mac_font_copy_uvs_table (CTFontRef font)
3087   CFDataRef cmap_table, uvs_table = NULL;
3089   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3090                                 kCTFontTableOptionNoOptions);
3091   if (cmap_table)
3092     {
3093       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3094       struct uvs_table *uvs;
3095       struct variation_selector_record *records;
3096       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3098 #if __LP64__
3099       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3100         goto finish;
3101 #endif
3103       cmap_len = CFDataGetLength (cmap_table);
3104       if (sizeof_sfntCMapHeader > cmap_len)
3105         goto finish;
3107       ntables = BUINT16_VALUE (cmap->numTables);
3108       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3109                      / sizeof_sfntCMapEncoding))
3110         goto finish;
3112       for (i = 0; i < ntables; i++)
3113         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3114              == kFontUnicodePlatform)
3115             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3116                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3117           {
3118             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3119             break;
3120           }
3121       if (i == ntables
3122           || uvs_offset > cmap_len
3123           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3124         goto finish;
3126       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3127       uvs_len = BUINT32_VALUE (uvs->length);
3128       if (uvs_len > cmap_len - uvs_offset
3129           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3130         goto finish;
3132       if (BUINT16_VALUE (uvs->format) != 14)
3133         goto finish;
3135       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3136       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3137                       / sizeof (struct variation_selector_record)))
3138         goto finish;
3140       records = uvs->variation_selector_records;
3141       for (i = 0; i < nrecords; i++)
3142         {
3143           UInt32 default_uvs_offset, non_default_uvs_offset;
3145           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3146           if (default_uvs_offset)
3147             {
3148               struct default_uvs_table *default_uvs;
3149               UInt32 nranges;
3151               if (default_uvs_offset > uvs_len
3152                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3153                       > uvs_len - default_uvs_offset))
3154                 goto finish;
3156               default_uvs = ((struct default_uvs_table *)
3157                              ((UInt8 *) uvs + default_uvs_offset));
3158               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3159               if (nranges > ((uvs_len - default_uvs_offset
3160                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3161                              / sizeof (struct unicode_value_range)))
3162                 goto finish;
3163               /* Now 2 * nranges can't overflow, so we can safely use
3164                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3165                  mac_font_get_glyphs_for_variants.  */
3166             }
3168           non_default_uvs_offset =
3169             BUINT32_VALUE (records[i].non_default_uvs_offset);
3170           if (non_default_uvs_offset)
3171             {
3172               struct non_default_uvs_table *non_default_uvs;
3173               UInt32 nmappings;
3175               if (non_default_uvs_offset > uvs_len
3176                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3177                       > uvs_len - non_default_uvs_offset))
3178                 goto finish;
3180               non_default_uvs = ((struct non_default_uvs_table *)
3181                                  ((UInt8 *) uvs + non_default_uvs_offset));
3182               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3183               if (nmappings > ((uvs_len - non_default_uvs_offset
3184                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3185                                / sizeof (struct uvs_mapping)))
3186                 goto finish;
3187               /* Now 2 * nmappings can't overflow, so we can safely
3188                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3189                  in mac_font_get_glyphs_for_variants.  */
3190             }
3191         }
3193       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3195     finish:
3196       CFRelease (cmap_table);
3197     }
3199   return uvs_table;
3202 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3203    sequence consisting of the given base character C and each
3204    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3205    result (explained below) into the corresponding GLYPHS[i].  If the
3206    entry is found in the Default UVS Table, then the result is 0.  If
3207    the entry is found in the Non-Default UVS Table, then the result is
3208    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3209    elements in SELECTORS must be sorted in strictly increasing
3210    order.  */
3212 static void
3213 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3214                                   const UTF32Char selectors[], CGGlyph glyphs[],
3215                                   CFIndex count)
3217   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3218   struct variation_selector_record *records = uvs->variation_selector_records;
3219   CFIndex i;
3220   UInt32 ir, nrecords;
3221   dispatch_queue_t queue =
3222     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3223   dispatch_group_t group = dispatch_group_create ();
3225   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3226   i = 0;
3227   ir = 0;
3228   while (i < count && ir < nrecords)
3229     {
3230       UInt32 default_uvs_offset, non_default_uvs_offset;
3232       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3233         {
3234           glyphs[i++] = kCGFontIndexInvalid;
3235           continue;
3236         }
3237       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3238         {
3239           ir++;
3240           continue;
3241         }
3243       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3244       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3245       non_default_uvs_offset =
3246         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3247       dispatch_group_async (group, queue, ^{
3248           glyphs[i] = kCGFontIndexInvalid;
3250           if (default_uvs_offset)
3251             {
3252               struct default_uvs_table *default_uvs =
3253                 (struct default_uvs_table *) ((UInt8 *) uvs
3254                                               + default_uvs_offset);
3255               struct unicode_value_range *ranges =
3256                 default_uvs->unicode_value_ranges;
3257               UInt32 lo, hi;
3259               lo = 0;
3260               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3261               while (lo < hi)
3262                 {
3263                   UInt32 mid = (lo + hi) / 2;
3265                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3266                     hi = mid;
3267                   else
3268                     lo = mid + 1;
3269                 }
3270               if (hi > 0
3271                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3272                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3273                 glyphs[i] = 0;
3274             }
3276           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3277             {
3278               struct non_default_uvs_table *non_default_uvs =
3279                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3280                                                   + non_default_uvs_offset);
3281               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3282               UInt32 lo, hi;
3284               lo = 0;
3285               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3286               while (lo < hi)
3287                 {
3288                   UInt32 mid = (lo + hi) / 2;
3290                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3291                     hi = mid;
3292                   else
3293                     lo = mid + 1;
3294                 }
3295               if (hi > 0 &&
3296                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3297                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3298             }
3299         });
3300       i++;
3301       ir++;
3302     }
3303   while (i < count)
3304     glyphs[i++] = kCGFontIndexInvalid;
3305   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3306   dispatch_release (group);
3309 static int
3310 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3312   CFDataRef uvs_table;
3313   CTCharacterCollection uvs_collection;
3314   int i, n = 0;
3316   block_input ();
3317   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3319   if (uvs_table)
3320     {
3321       UTF32Char selectors[256];
3322       CGGlyph glyphs[256];
3324       for (i = 0; i < 16; i++)
3325         selectors[i] = 0xFE00 + i;
3326       for (; i < 256; i++)
3327         selectors[i] = 0xE0100 + (i - 16);
3328       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3329       for (i = 0; i < 256; i++)
3330         {
3331           CGGlyph glyph = glyphs[i];
3333           if (uvs_collection != kCTCharacterCollectionIdentityMapping
3334               && glyph != kCGFontIndexInvalid)
3335             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3336           if (glyph == kCGFontIndexInvalid)
3337             variations[i] = 0;
3338           else
3339             {
3340               variations[i] = (glyph ? glyph
3341                                : macfont_get_glyph_for_character (font, c));
3342               n++;
3343             }
3344         }
3345     }
3346   unblock_input ();
3348   return n;
3351 static const char *const macfont_booleans[] = {
3352   ":antialias",
3353   ":minspace",
3354   NULL,
3357 static const char *const macfont_non_booleans[] = {
3358   ":lang",
3359   ":script",
3360   ":destination",
3361   NULL,
3364 static void
3365 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3367   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3370 static Boolean
3371 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3372                                         CFArrayRef languages)
3374   Boolean result = true;
3375   CFArrayRef desc_languages =
3376     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3378   if (desc_languages == NULL)
3379     result = false;
3380   else
3381     {
3382       CFIndex desc_languages_count, i, languages_count;
3384       desc_languages_count = CFArrayGetCount (desc_languages);
3385       languages_count = CFArrayGetCount (languages);
3386       for (i = 0; i < languages_count; i++)
3387         if (!CFArrayContainsValue (desc_languages,
3388                                    CFRangeMake (0, desc_languages_count),
3389                                    CFArrayGetValueAtIndex (languages, i)))
3390           {
3391             result = false;
3392             break;
3393           }
3394       CFRelease (desc_languages);
3395     }
3397   return result;
3400 static CFStringRef
3401 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3403   CFStringRef result = NULL;
3404   CFStringRef charset_string =
3405     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3407   if (charset_string && CFStringGetLength (charset_string) > 0)
3408     {
3409       CFStringRef keys[] = {
3410 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3411         kCTLanguageAttributeName
3412 #else
3413         CFSTR ("NSLanguage")
3414 #endif
3415       };
3416       CFTypeRef values[] = {NULL};
3417       CFIndex num_values = 0;
3418       CFArrayRef languages
3419         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3421       if (languages && CFArrayGetCount (languages) > 0)
3422         {
3423           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3424             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3425           else
3426             {
3427               CFCharacterSetRef charset =
3428                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3430               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3431             }
3432         }
3433       if (result == NULL)
3434         {
3435           CFAttributedStringRef attr_string = NULL;
3436           CTLineRef ctline = NULL;
3437           CFDictionaryRef attrs
3438             = CFDictionaryCreate (NULL, (const void **) keys,
3439                                   (const void **) values, num_values,
3440                                   &kCFTypeDictionaryKeyCallBacks,
3441                                   &kCFTypeDictionaryValueCallBacks);
3443           if (attrs)
3444             {
3445               attr_string = CFAttributedStringCreate (NULL, charset_string,
3446                                                       attrs);
3447               CFRelease (attrs);
3448             }
3449           if (attr_string)
3450             {
3451               ctline = CTLineCreateWithAttributedString (attr_string);
3452               CFRelease (attr_string);
3453             }
3454           if (ctline)
3455             {
3456               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3457               CFIndex i, nruns = CFArrayGetCount (runs);
3458               CTFontRef font;
3460               for (i = 0; i < nruns; i++)
3461                 {
3462                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3463                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3464                   CTFontRef font_in_run;
3466                   if (attributes == NULL)
3467                     break;
3468                   font_in_run =
3469                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3470                   if (font_in_run == NULL)
3471                     break;
3472                   if (i == 0)
3473                     font = font_in_run;
3474                   else if (!mac_font_equal_in_postscript_name (font,
3475                                                                font_in_run))
3476                     break;
3477                 }
3478               if (nruns > 0 && i == nruns)
3479                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3480               CFRelease (ctline);
3481             }
3482         }
3483     }
3485   return result;
3488 static inline double
3489 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3491   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3492                                      &glyph, NULL, 1);
3495 static inline CGRect
3496 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3498   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3499                                           &glyph, NULL, 1);
3502 static CFArrayRef
3503 mac_font_create_available_families (void)
3505   CFMutableArrayRef families = NULL;
3506   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3508   if (orig_families)
3509     {
3510       CFIndex i, count = CFArrayGetCount (orig_families);
3512       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3513       if (families)
3514         for (i = 0; i < count; i++)
3515           {
3516             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3518             if (!CFStringHasPrefix (family, CFSTR ("."))
3519                 && (CTFontManagerCompareFontFamilyNames (family,
3520                                                          CFSTR ("LastResort"),
3521                                                          NULL)
3522                     != kCFCompareEqualTo))
3523               CFArrayAppendValue (families, family);
3524           }
3525       CFRelease (orig_families);
3526     }
3528   return families;
3531 static Boolean
3532 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3534   Boolean result;
3535   CFStringRef name1, name2;
3537   if (font1 == font2)
3538     return true;
3540   result = false;
3541   name1 = CTFontCopyPostScriptName (font1);
3542   if (name1)
3543     {
3544       name2 = CTFontCopyPostScriptName (font2);
3545       if (name2)
3546         {
3547           result = CFEqual (name1, name2);
3548           CFRelease (name2);
3549         }
3550       CFRelease (name1);
3551     }
3553   return result;
3556 static CTLineRef
3557 mac_font_create_line_with_string_and_font (CFStringRef string,
3558                                            CTFontRef macfont)
3560   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3561   CFTypeRef values[] = {NULL, NULL};
3562   CFDictionaryRef attributes = NULL;
3563   CFAttributedStringRef attr_string = NULL;
3564   CTLineRef ctline = NULL;
3565   float float_zero = 0.0f;
3567   values[0] = macfont;
3568   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3569   if (values[1])
3570     {
3571       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3572                                        (const void **) values,
3573                                        ARRAYELTS (keys),
3574                                        &kCFTypeDictionaryKeyCallBacks,
3575                                        &kCFTypeDictionaryValueCallBacks);
3576       CFRelease (values[1]);
3577     }
3578   if (attributes)
3579     {
3580       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3581       CFRelease (attributes);
3582     }
3583   if (attr_string)
3584     {
3585       ctline = CTLineCreateWithAttributedString (attr_string);
3586       CFRelease (attr_string);
3587     }
3588   if (ctline)
3589     {
3590       /* Abandon if ctline contains some fonts other than the
3591          specified one.  */
3592       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3593       CFIndex i, nruns = CFArrayGetCount (runs);
3595       for (i = 0; i < nruns; i++)
3596         {
3597           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3598           CFDictionaryRef attributes = CTRunGetAttributes (run);
3599           CTFontRef font_in_run;
3601           if (attributes == NULL)
3602             break;
3603           font_in_run =
3604             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3605           if (font_in_run == NULL)
3606             break;
3607           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3608             break;
3609         }
3610       if (i < nruns)
3611         {
3612           CFRelease (ctline);
3613           ctline = NULL;
3614         }
3615     }
3617   return ctline;
3620 static CFIndex
3621 mac_font_shape (CTFontRef font, CFStringRef string,
3622                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3624   CFIndex used, result = 0;
3625   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3627   if (ctline == NULL)
3628     return 0;
3630   used = CTLineGetGlyphCount (ctline);
3631   if (used <= glyph_len)
3632     {
3633       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3634       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3635       CGFloat total_advance = 0;
3636       CFIndex total_glyph_count = 0;
3638       for (k = 0; k < ctrun_count; k++)
3639         {
3640           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3641           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3642           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3643           CFRange string_range, comp_range, range;
3644           CFIndex *permutation;
3646           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3647             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3648           else
3649             permutation = NULL;
3651 #define RIGHT_TO_LEFT_P permutation
3653           /* Now the `comp_range' member of struct mac_glyph_layout is
3654              temporarily used as a work area such that:
3655              glbuf[i].comp_range.location =
3656              min {compRange[i + 1].location, ...,
3657                      compRange[glyph_count - 1].location,
3658                      maxRange (stringRangeForCTRun)}
3659              glbuf[i].comp_range.length = maxRange (compRange[i])
3660              where compRange[i] is the range of composed characters
3661              containing i-th glyph.  */
3662           string_range = CTRunGetStringRange (ctrun);
3663           min_location = string_range.location + string_range.length;
3664           for (i = 0; i < glyph_count; i++)
3665             {
3666               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3667               CFIndex glyph_index;
3668               CFRange rng;
3670               if (!RIGHT_TO_LEFT_P)
3671                 glyph_index = glyph_count - i - 1;
3672               else
3673                 glyph_index = i;
3674               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3675                                      &gl->string_index);
3676               rng =
3677                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3678                                                              gl->string_index);
3679               gl->comp_range.location = min_location;
3680               gl->comp_range.length = rng.location + rng.length;
3681               if (rng.location < min_location)
3682                 min_location = rng.location;
3683             }
3685           /* Fill the `comp_range' member of struct mac_glyph_layout,
3686              and setup a permutation for right-to-left text.  */
3687           comp_range = CFRangeMake (string_range.location, 0);
3688           range = CFRangeMake (0, 0);
3689           while (1)
3690             {
3691               struct mac_glyph_layout *gl =
3692                 glbuf + range.location + range.length;
3694               if (gl->comp_range.length
3695                   > comp_range.location + comp_range.length)
3696                 comp_range.length = gl->comp_range.length - comp_range.location;
3697               min_location = gl->comp_range.location;
3698               range.length++;
3700               if (min_location >= comp_range.location + comp_range.length)
3701                 {
3702                   comp_range.length = min_location - comp_range.location;
3703                   for (i = 0; i < range.length; i++)
3704                     {
3705                       glbuf[range.location + i].comp_range = comp_range;
3706                       if (RIGHT_TO_LEFT_P)
3707                         permutation[range.location + i] =
3708                           range.location + range.length - i - 1;
3709                     }
3711                   comp_range = CFRangeMake (min_location, 0);
3712                   range.location += range.length;
3713                   range.length = 0;
3714                   if (range.location == glyph_count)
3715                     break;
3716                 }
3717             }
3719           /* Then fill the remaining members.  */
3720           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3721                range.location++)
3722             {
3723               struct mac_glyph_layout *gl;
3724               CGPoint position;
3726               if (!RIGHT_TO_LEFT_P)
3727                 gl = glbuf + range.location;
3728               else
3729                 {
3730                   CFIndex src, dest;
3732                   src = glyph_count - 1 - range.location;
3733                   dest = permutation[src];
3734                   gl = glbuf + dest;
3735                   if (src < dest)
3736                     {
3737                       CFIndex tmp = gl->string_index;
3739                       gl->string_index = glbuf[src].string_index;
3740                       glbuf[src].string_index = tmp;
3741                     }
3742                 }
3743               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3745               CTRunGetPositions (ctrun, range, &position);
3746               gl->advance_delta = position.x - total_advance;
3747               gl->baseline_delta = position.y;
3748               gl->advance = (gl->advance_delta
3749                              + CTRunGetTypographicBounds (ctrun, range,
3750                                                           NULL, NULL, NULL));
3751               total_advance += gl->advance;
3752             }
3754           if (RIGHT_TO_LEFT_P)
3755             xfree (permutation);
3757 #undef RIGHT_TO_LEFT_P
3759           total_glyph_count += glyph_count;
3760         }
3762       result = used;
3763     }
3764   CFRelease (ctline);
3766   return result;
3769 /* The function below seems to cause a memory leak for the CFString
3770    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3771    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3772 #if USE_CT_GLYPH_INFO
3773 static CGGlyph
3774 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3775                               CGFontIndex cid)
3777   CGGlyph result = kCGFontIndexInvalid;
3778   UniChar characters[] = {0xfffd};
3779   CFStringRef string;
3780   CFAttributedStringRef attr_string = NULL;
3781   CTLineRef ctline = NULL;
3783   string = CFStringCreateWithCharacters (NULL, characters,
3784                                          ARRAYELTS (characters));
3786   if (string)
3787     {
3788       CTGlyphInfoRef glyph_info =
3789         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3790       CFDictionaryRef attributes = NULL;
3792       if (glyph_info)
3793         {
3794           CFStringRef keys[] = {kCTFontAttributeName,
3795                                 kCTGlyphInfoAttributeName};
3796           CFTypeRef values[] = {font, glyph_info};
3798           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3799                                            (const void **) values,
3800                                            ARRAYELTS (keys),
3801                                            &kCFTypeDictionaryKeyCallBacks,
3802                                            &kCFTypeDictionaryValueCallBacks);
3803           CFRelease (glyph_info);
3804         }
3805       if (attributes)
3806         {
3807           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3808           CFRelease (attributes);
3809         }
3810       CFRelease (string);
3811     }
3812   if (attr_string)
3813     {
3814       ctline = CTLineCreateWithAttributedString (attr_string);
3815       CFRelease (attr_string);
3816     }
3817   if (ctline)
3818     {
3819       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3821       if (CFArrayGetCount (runs) > 0)
3822         {
3823           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3824           CFDictionaryRef attributes = CTRunGetAttributes (run);
3826           if (attributes)
3827             {
3828               CTFontRef font_in_run =
3829                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3831               if (font_in_run
3832                   && mac_font_equal_in_postscript_name (font_in_run, font))
3833                 {
3834                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3835                   if (result >= CTFontGetGlyphCount (font))
3836                     result = kCGFontIndexInvalid;
3837                 }
3838             }
3839         }
3840       CFRelease (ctline);
3841     }
3843   return result;
3845 #endif
3847 static CFArrayRef
3848 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3850   CFArrayRef result = NULL;
3852 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3853 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3854   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3855 #endif
3856     {
3857       CTFontRef user_font =
3858         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3860       if (user_font)
3861         {
3862           CFArrayRef languages =
3863             CFArrayCreate (NULL, (const void **) &language, 1,
3864                            &kCFTypeArrayCallBacks);
3866           if (languages)
3867             {
3868               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3869                                                                  languages);
3870               CFRelease (languages);
3871             }
3872           CFRelease (user_font);
3873         }
3874     }
3875 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3876   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3877 #endif
3878 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3879 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3880     {
3881       CFIndex i;
3883       for (i = 0; macfont_language_default_font_names[i].language; i++)
3884         {
3885           if (CFEqual (macfont_language_default_font_names[i].language,
3886                        language))
3887             {
3888               CFMutableArrayRef descriptors =
3889                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3891               if (descriptors)
3892                 {
3893                   CFIndex j;
3895                   for (j = 0;
3896                        macfont_language_default_font_names[i].font_names[j];
3897                        j++)
3898                     {
3899                       CFDictionaryRef attributes =
3900                         CFDictionaryCreate (NULL,
3901                                             ((const void **)
3902                                              &kCTFontNameAttribute),
3903                                             ((const void **)
3904                                              &macfont_language_default_font_names[i].font_names[j]),
3905                                             1, &kCFTypeDictionaryKeyCallBacks,
3906                                             &kCFTypeDictionaryValueCallBacks);
3908                       if (attributes)
3909                         {
3910                           CTFontDescriptorRef pat_desc =
3911                             CTFontDescriptorCreateWithAttributes (attributes);
3913                           if (pat_desc)
3914                             {
3915                               CTFontDescriptorRef descriptor =
3916                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3918                               if (descriptor)
3919                                 {
3920                                   CFArrayAppendValue (descriptors, descriptor);
3921                                   CFRelease (descriptor);
3922                                 }
3923                               CFRelease (pat_desc);
3924                             }
3925                           CFRelease (attributes);
3926                         }
3927                     }
3928                   result = descriptors;
3929                 }
3930               break;
3931             }
3932         }
3933     }
3934 #endif
3936   return result;
3939 static CFStringRef
3940 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3941                                                       CFArrayRef languages)
3943   CFStringRef result = NULL;
3944   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3945   CFArrayRef descriptors =
3946     mac_font_copy_default_descriptors_for_language (language);
3948   if (descriptors)
3949     {
3950       CFIndex i, count = CFArrayGetCount (descriptors);
3952       for (i = 0; i < count; i++)
3953         {
3954           CTFontDescriptorRef descriptor =
3955             CFArrayGetValueAtIndex (descriptors, i);
3957           if (macfont_supports_charset_and_languages_p (descriptor, charset,
3958                                                         Qnil, languages))
3959             {
3960               CFStringRef family =
3961                 CTFontDescriptorCopyAttribute (descriptor,
3962                                                kCTFontFamilyNameAttribute);
3963               if (family)
3964                 {
3965                   if (!CFStringHasPrefix (family, CFSTR ("."))
3966                       && !CFEqual (family, CFSTR ("LastResort")))
3967                     {
3968                       result = family;
3969                       break;
3970                     }
3971                   else
3972                     CFRelease (family);
3973                 }
3974             }
3975         }
3976       CFRelease (descriptors);
3977     }
3979   return result;
3982 void *
3983 macfont_get_nsctfont (struct font *font)
3985   struct macfont_info *macfont_info = (struct macfont_info *) font;
3986   CTFontRef macfont = macfont_info->macfont;
3988   return (void *) macfont;
3991 void
3992 mac_register_font_driver (struct frame *f)
3994   register_font_driver (&macfont_driver, f);
3998 void
3999 syms_of_macfont (void)
4001   static struct font_driver mac_font_driver;
4003   /* Core Text, for Mac OS X.  */
4004   DEFSYM (Qmac_ct, "mac-ct");
4005   macfont_driver.type = Qmac_ct;
4006   register_font_driver (&macfont_driver, NULL);
4008   /* The font property key specifying the font design destination.  The
4009      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4010      text.  (See the documentation of X Logical Font Description
4011      Conventions.)  In the Mac font driver, 1 means the screen font is
4012      used for calculating some glyph metrics.  You can see the
4013      difference with Monaco 8pt or 9pt, for example.  */
4014   DEFSYM (QCdestination, ":destination");
4016   /* The boolean-valued font property key specifying the use of leading.  */
4017   DEFSYM (QCminspace, ":minspace");
4019   macfont_family_cache = Qnil;
4020   staticpro (&macfont_family_cache);