Doc fix.
[emacs.git] / src / macfont.m
blobc284b3086f83ddcd91947be97b476f61ebb8276c
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2013 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 "nsgui.h"
34 #include "nsterm.h"
35 #include "macfont.h"
36 #include "macuvs.h"
38 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
40 #include <libkern/OSByteOrder.h>
42 static struct font_driver macfont_driver;
44 /* Core Text, for Mac OS X 10.5 and later.  */
45 static Lisp_Object Qmac_ct;
47 static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
48 static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
49 static CFArrayRef mac_ctfont_create_available_families (void);
50 static Boolean mac_ctfont_equal_in_postscript_name (CTFontRef, CTFontRef);
51 static CTLineRef mac_ctfont_create_line_with_string_and_font (CFStringRef,
52                                                               CTFontRef);
53 static CFComparisonResult mac_font_family_compare (const void *,
54                                                    const void *, void *);
55 static Boolean mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef,
56                                                          CFArrayRef);
57 static CFStringRef mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef);
58 static CFIndex mac_ctfont_shape (CTFontRef, CFStringRef,
59                                  struct mac_glyph_layout *, CFIndex);
60 #if USE_CT_GLYPH_INFO
61 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef,
62                                              CTCharacterCollection,
63                                              CGFontIndex);
64 #endif
66 /* The font property key specifying the font design destination.  The
67    value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
68    text.  (See the documentation of X Logical Font Description
69    Conventions.)  In the Mac font driver, 1 means the screen font is
70    used for calculating some glyph metrics.  You can see the
71    difference with Monaco 8pt or 9pt, for example.  */
72 static Lisp_Object QCdestination;
74 /* The boolean-valued font property key specifying the use of
75    leading.  */
76 static Lisp_Object QCminspace;
78 struct macfont_metrics;
80 /* The actual structure for Mac font that can be casted to struct font.  */
82 struct macfont_info
84   struct font font;
85   FontRef macfont;
86   CGFontRef cgfont;
87   ScreenFontRef screen_font;
88   struct macfont_cache *cache;
89   struct macfont_metrics **metrics;
90   short metrics_nrows;
91   unsigned synthetic_italic_p : 1;
92   unsigned synthetic_bold_p : 1;
93   unsigned spacing : 2;
94   unsigned antialias : 2;
95   unsigned color_bitmap_p : 1;
98 /* Values for the `spacing' member in `struct macfont_info'.  */
100 enum
101   {
102     MACFONT_SPACING_PROPORTIONAL,
103     MACFONT_SPACING_MONO,
104     MACFONT_SPACING_SYNTHETIC_MONO,
105   };
107 /* Values for the `antialias' member in `struct macfont_info'.  */
109 enum
110   {
111     MACFONT_ANTIALIAS_DEFAULT,
112     MACFONT_ANTIALIAS_OFF,
113     MACFONT_ANTIALIAS_ON,
114   };
116 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
117 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
118 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
120 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
121 static const CGFloat synthetic_bold_factor = 0.024;
123 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
124                                                         FontSymbolicTraits *);
125 static void macfont_store_descriptor_attributes (FontDescriptorRef,
126                                                  Lisp_Object);
127 static Lisp_Object macfont_descriptor_entity (FontDescriptorRef,
128                                               Lisp_Object,
129                                               FontSymbolicTraits);
130 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
131 static int macfont_glyph_extents (struct font *, CGGlyph,
132                                   struct font_metrics *, CGFloat *, int);
133 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
134 static Boolean macfont_supports_charset_and_languages_p (FontDescriptorRef,
135                                                          CFCharacterSetRef,
136                                                          Lisp_Object,
137                                                          CFArrayRef);
138 static CFIndex macfont_closest_traits_index (CFArrayRef,
139                                              FontSymbolicTraits);
140 static CFDataRef mac_font_copy_uvs_table (FontRef);
141 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
142                                               const UTF32Char [],
143                                               CGGlyph [], CFIndex);
145 /* From CFData to a lisp string.  Always returns a unibyte string.  */
147 static Lisp_Object
148 cfdata_to_lisp (CFDataRef data)
150   CFIndex len = CFDataGetLength (data);
151   Lisp_Object result = make_uninit_string (len);
153   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
155   return result;
160 /* From CFString to a lisp string.  Returns a unibyte string
161    containing a UTF-8 byte sequence.  */
163 static Lisp_Object
164 cfstring_to_lisp_nodecode (CFStringRef string)
166   Lisp_Object result = Qnil;
167   CFDataRef data;
168   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
170   if (s)
171     {
172       CFIndex i, length = CFStringGetLength (string);
174       for (i = 0; i < length; i++)
175         if (CFStringGetCharacterAtIndex (string, i) == 0)
176           break;
178       if (i == length)
179         return make_unibyte_string (s, strlen (s));
180     }
182   data = CFStringCreateExternalRepresentation (NULL, string,
183                                                kCFStringEncodingUTF8, '?');
184   if (data)
185     {
186       result = cfdata_to_lisp (data);
187       CFRelease (data);
188     }
190   return result;
193 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
194    cfstring_create_with_utf8_cstring, this function preserves NUL
195    characters.  */
197 static CFStringRef
198 cfstring_create_with_string_noencode (Lisp_Object s)
200   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
201                                                 kCFStringEncodingUTF8, false);
203   if (string == NULL)
204     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
205     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
206                                       kCFStringEncodingMacRoman, false);
208   return string;
211 static CGFloat
212 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
214   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
216   return advancement.width;
219 static CGGlyph
220 mac_font_get_glyph_for_cid (FontRef font, CharacterCollection collection,
221                             CGFontIndex cid)
223 #if USE_CT_GLYPH_INFO
224   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
225 #else
226   {
227     CGGlyph result = kCGFontIndexInvalid;
228     NSFont *nsFont = (NSFont *) font;
229     unichar characters[] = {0xfffd};
230     NSString *string =
231       [NSString stringWithCharacters:characters
232                               length:(sizeof (characters)
233                                       / sizeof (characters[0]))];
234     NSGlyphInfo *glyphInfo =
235       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
236                                          collection:collection
237                                          baseString:string];
238     NSDictionary *attributes =
239       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
240                     glyphInfo,NSGlyphInfoAttributeName,nil];
241     NSTextStorage *textStorage =
242       [[NSTextStorage alloc] initWithString:string
243                                  attributes:attributes];
244     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
245     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
246     NSFont *fontInTextStorage;
248     [layoutManager addTextContainer:textContainer];
249     [textContainer release];
250     [textStorage addLayoutManager:layoutManager];
251     [layoutManager release];
253     /* Force layout.  */
254     (void) [layoutManager glyphRangeForTextContainer:textContainer];
256     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
257                                 effectiveRange:NULL];
258     if (fontInTextStorage == nsFont
259         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
260       {
261         NSGlyph glyph = [layoutManager glyphAtIndex:0];
263         if (glyph < [nsFont numberOfGlyphs])
264           result = glyph;
265       }
267     [textStorage release];
269     return result;
270   }
272 #endif
274 static ScreenFontRef
275 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
277   NSFont *result, *font;
279   font = [NSFont fontWithName:((NSString *) name) size:size];
280   result = [font screenFont];
282   return (ScreenFontRef)[result retain];
286 static Boolean
287 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
288                              CGFloat *descent, CGFloat *leading)
290   NSFont *nsFont = [(NSFont *)font printerFont];
291   NSTextStorage *textStorage;
292   NSLayoutManager *layoutManager;
293   NSTextContainer *textContainer;
294   NSRect usedRect;
295   NSPoint spaceLocation;
296   CGFloat descender;
298   textStorage = [[NSTextStorage alloc] initWithString:@" "];
299   layoutManager = [[NSLayoutManager alloc] init];
300   textContainer = [[NSTextContainer alloc] init];
302   [textStorage setFont:nsFont];
303   [textContainer setLineFragmentPadding:0];
304   [layoutManager setUsesScreenFonts:YES];
306   [layoutManager addTextContainer:textContainer];
307   [textContainer release];
308   [textStorage addLayoutManager:layoutManager];
309   [layoutManager release];
311   if (!(textStorage && layoutManager && textContainer))
312     {
313       [textStorage release];
315       return false;
316     }
318   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
319                                                  effectiveRange:NULL];
320   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
321   [textStorage release];
323   *ascent = spaceLocation.y;
324   *descent = NSHeight (usedRect) - spaceLocation.y;
325   *leading = 0;
326   descender = [nsFont descender];
327   if (- descender < *descent)
328     {
329       *leading = *descent + descender;
330       *descent = - descender;
331     }
333   return true;
336 static CFIndex
337 mac_font_shape_1 (NSFont *font, NSString *string,
338                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
339                   BOOL screen_font_p)
341   NSUInteger i;
342   CFIndex result = 0;
343   NSTextStorage *textStorage;
344   NSLayoutManager *layoutManager;
345   NSTextContainer *textContainer;
346   NSUInteger stringLength;
347   NSPoint spaceLocation;
348   NSUInteger used, numberOfGlyphs;
350   textStorage = [[NSTextStorage alloc] initWithString:string];
351   layoutManager = [[NSLayoutManager alloc] init];
352   textContainer = [[NSTextContainer alloc] init];
354   /* Append a trailing space to measure baseline position.  */
355   [textStorage appendAttributedString:([[[NSAttributedString alloc]
356                                           initWithString:@" "] autorelease])];
357   [textStorage setFont:font];
358   [textContainer setLineFragmentPadding:0];
359   [layoutManager setUsesScreenFonts:screen_font_p];
361   [layoutManager addTextContainer:textContainer];
362   [textContainer release];
363   [textStorage addLayoutManager:layoutManager];
364   [layoutManager release];
366   if (!(textStorage && layoutManager && textContainer))
367     {
368       [textStorage release];
370       return 0;
371     }
373   stringLength = [string length];
375   /* Force layout.  */
376   (void) [layoutManager glyphRangeForTextContainer:textContainer];
378   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
380   /* Remove the appended trailing space because otherwise it may
381      generate a wrong result for a right-to-left text.  */
382   [textStorage beginEditing];
383   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
384   [textStorage endEditing];
385   (void) [layoutManager glyphRangeForTextContainer:textContainer];
387   i = 0;
388   while (i < stringLength)
389     {
390       NSRange range;
391       NSFont *fontInTextStorage =
392         [textStorage attribute:NSFontAttributeName atIndex:i
393                      longestEffectiveRange:&range
394                        inRange:(NSMakeRange (0, stringLength))];
396       if (!(fontInTextStorage == font
397             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
398         break;
399       i = NSMaxRange (range);
400     }
401   if (i < stringLength)
402     /* Make the test `used <= glyph_len' below fail if textStorage
403        contained some fonts other than the specified one.  */
404     used = glyph_len + 1;
405   else
406     {
407       NSRange range = NSMakeRange (0, stringLength);
409       range = [layoutManager glyphRangeForCharacterRange:range
410                                     actualCharacterRange:NULL];
411       numberOfGlyphs = NSMaxRange (range);
412       used = numberOfGlyphs;
413       for (i = 0; i < numberOfGlyphs; i++)
414         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
415           used--;
416     }
418   if (0 < used && used <= glyph_len)
419     {
420       NSUInteger glyphIndex, prevGlyphIndex;
421       unsigned char bidiLevel;
422       NSUInteger *permutation;
423       NSRange compRange, range;
424       CGFloat totalAdvance;
426       glyphIndex = 0;
427       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
428         glyphIndex++;
430       /* For now we assume the direction is not changed within the
431          string.  */
432       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
433                                glyphs:NULL characterIndexes:NULL
434                     glyphInscriptions:NULL elasticBits:NULL
435                            bidiLevels:&bidiLevel];
436       if (bidiLevel & 1)
437         permutation = xmalloc (sizeof (NSUInteger) * used);
438       else
439         permutation = NULL;
441 #define RIGHT_TO_LEFT_P permutation
443       /* Fill the `comp_range' member of struct mac_glyph_layout, and
444          setup a permutation for right-to-left text.  */
445       compRange = NSMakeRange (0, 0);
446       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
447            range.length++)
448         {
449           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
450           NSUInteger characterIndex =
451             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
453           gl->string_index = characterIndex;
455           if (characterIndex >= NSMaxRange (compRange))
456             {
457               compRange.location = NSMaxRange (compRange);
458               do
459                 {
460                   NSRange characterRange =
461                     [string
462                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
464                   compRange.length =
465                     NSMaxRange (characterRange) - compRange.location;
466                   [layoutManager glyphRangeForCharacterRange:compRange
467                                         actualCharacterRange:&characterRange];
468                   characterIndex = NSMaxRange (characterRange) - 1;
469                 }
470               while (characterIndex >= NSMaxRange (compRange));
472               if (RIGHT_TO_LEFT_P)
473                 for (i = 0; i < range.length; i++)
474                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
476               range = NSMakeRange (NSMaxRange (range), 0);
477             }
479           gl->comp_range.location = compRange.location;
480           gl->comp_range.length = compRange.length;
482           while (++glyphIndex < numberOfGlyphs)
483             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
484               break;
485         }
486       if (RIGHT_TO_LEFT_P)
487         for (i = 0; i < range.length; i++)
488           permutation[range.location + i] = NSMaxRange (range) - i - 1;
490       /* Then fill the remaining members.  */
491       glyphIndex = prevGlyphIndex = 0;
492       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
493         glyphIndex++;
495       if (!RIGHT_TO_LEFT_P)
496         totalAdvance = 0;
497       else
498         {
499           NSUInteger nrects;
500           NSRect *glyphRects =
501             [layoutManager
502               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
503               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
504                      inTextContainer:textContainer rectCount:&nrects];
506           totalAdvance = NSMaxX (glyphRects[0]);
507         }
509       for (i = 0; i < used; i++)
510         {
511           struct mac_glyph_layout *gl;
512           NSPoint location;
513           NSUInteger nextGlyphIndex;
514           NSRange glyphRange;
515           NSRect *glyphRects;
516           NSUInteger nrects;
518           if (!RIGHT_TO_LEFT_P)
519             gl = glyph_layouts + i;
520           else
521             {
522               NSUInteger dest = permutation[i];
524               gl = glyph_layouts + dest;
525               if (i < dest)
526                 {
527                   CFIndex tmp = gl->string_index;
529                   gl->string_index = glyph_layouts[i].string_index;
530                   glyph_layouts[i].string_index = tmp;
531                 }
532             }
533           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
535           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
536           gl->baseline_delta = spaceLocation.y - location.y;
538           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
539                nextGlyphIndex++)
540             if (![layoutManager
541                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
542               break;
544           if (!RIGHT_TO_LEFT_P)
545             {
546               CGFloat maxX;
548               if (prevGlyphIndex == 0)
549                 glyphRange = NSMakeRange (0, nextGlyphIndex);
550               else
551                 glyphRange = NSMakeRange (glyphIndex,
552                                           nextGlyphIndex - glyphIndex);
553               glyphRects =
554                 [layoutManager
555                   rectArrayForGlyphRange:glyphRange
556                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
557                          inTextContainer:textContainer rectCount:&nrects];
558               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
559               gl->advance_delta = location.x - totalAdvance;
560               gl->advance = maxX - totalAdvance;
561               totalAdvance = maxX;
562             }
563           else
564             {
565               CGFloat minX;
567               if (nextGlyphIndex == numberOfGlyphs)
568                 glyphRange = NSMakeRange (prevGlyphIndex,
569                                           numberOfGlyphs - prevGlyphIndex);
570               else
571                 glyphRange = NSMakeRange (prevGlyphIndex,
572                                           glyphIndex + 1 - prevGlyphIndex);
573               glyphRects =
574                 [layoutManager
575                   rectArrayForGlyphRange:glyphRange
576                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
577                          inTextContainer:textContainer rectCount:&nrects];
578               minX = min (NSMinX (glyphRects[0]), totalAdvance);
579               gl->advance = totalAdvance - minX;
580               totalAdvance = minX;
581               gl->advance_delta = location.x - totalAdvance;
582             }
584           prevGlyphIndex = glyphIndex + 1;
585           glyphIndex = nextGlyphIndex;
586         }
588       if (RIGHT_TO_LEFT_P)
589         xfree (permutation);
591 #undef RIGHT_TO_LEFT_P
593       result = used;
594    }
595  [textStorage release];
597   return result;
600 static CFIndex
601 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
602                        struct mac_glyph_layout *glyph_layouts,
603                        CFIndex glyph_len)
605   return mac_font_shape_1 ([(NSFont *)font printerFont],
606                            (NSString *) string,
607                            glyph_layouts, glyph_len, YES);
610 static CGColorRef
611 get_cgcolor(unsigned long idx, struct frame *f)
613   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
614   [nsColor set];
615   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
616   NSInteger noc = [nsColor numberOfComponents];
617   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
618   CGColorRef cgColor;
620   [nsColor getComponents: components];
621   cgColor = CGColorCreate (colorSpace, components);
622   xfree (components);
623   return cgColor;
626 #define CG_SET_FILL_COLOR_WITH_GC_FOREGROUND(context, s)                \
627   do {                                                                  \
628     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (s->face),     \
629                                       s->f);                            \
630     CGContextSetFillColorWithColor (context, refcol_) ;                 \
631     CGColorRelease (refcol_);                                           \
632   } while (0)
633 #define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, s)                \
634   do {                                                                  \
635     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (s->face),\
636                                       s->f);                            \
637     CGContextSetFillColorWithColor (context, refcol_);                  \
638     CGColorRelease (refcol_);                                           \
639   } while (0)
640 #define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, s)              \
641   do {                                                                  \
642     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (s->face),\
643                                       s->f);                            \
644     CGContextSetStrokeColorWithColor (context, refcol_);                \
645     CGColorRelease (refcol_);                                           \
646   } while (0)
649 /* Mac font driver.  */
651 static struct
653   /* registry name */
654   const char *name;
655   /* characters to distinguish the charset from the others */
656   int uniquifier[6];
657   /* additional constraint by language */
658   CFStringRef lang;
659   /* set on demand */
660   CFCharacterSetRef cf_charset;
661   CFStringRef cf_charset_string;
662 } cf_charset_table[] =
663   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
664     { "iso8859-2", { 0x00A0, 0x010E }},
665     { "iso8859-3", { 0x00A0, 0x0108 }},
666     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
667     { "iso8859-5", { 0x00A0, 0x0401 }},
668     { "iso8859-6", { 0x00A0, 0x060C }},
669     { "iso8859-7", { 0x00A0, 0x0384 }},
670     { "iso8859-8", { 0x00A0, 0x05D0 }},
671     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
672     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
673     { "iso8859-11", { 0x00A0, 0x0E01 }},
674     { "iso8859-13", { 0x00A0, 0x201C }},
675     { "iso8859-14", { 0x00A0, 0x0174 }},
676     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
677     { "iso8859-16", { 0x00A0, 0x0218}},
678     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
679     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0xF7E5 }, CFSTR ("zh-Hant") },
680     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
681     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
682     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
683     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
684     { "cns11643.1992-3", { 0x201A9 }},
685     { "cns11643.1992-4", { 0x20057 }},
686     { "cns11643.1992-5", { 0x20000 }},
687     { "cns11643.1992-6", { 0x20003 }},
688     { "cns11643.1992-7", { 0x20055 }},
689     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
690     { "jisx0212.1990-0", { 0x4E44 }},
691     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
692     { "jisx0213.2000-2", { 0xFA49 }},
693     { "jisx0213.2004-1", { 0x20B9F }},
694     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
695     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
696     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
697     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
698     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
699     { "unicode-sip", { 0x20000 }},
700     { NULL }
701   };
703 static CGFloat macfont_antialias_threshold;
705 void
706 macfont_update_antialias_threshold (void)
708   int threshold;
709   Boolean valid_p;
711   threshold =
712     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
713                                      kCFPreferencesCurrentApplication,
714                                      &valid_p);
715   if (valid_p)
716     macfont_antialias_threshold = threshold;
719 static inline Lisp_Object
720 macfont_intern_prop_cfstring (CFStringRef cfstring)
722   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
724   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
727 static inline CFIndex
728 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
730   if (c < 0x10000)
731     {
732       unichars[0] = c;
734       return 1;
735     }
736   else
737     {
738       c -= 0x10000;
739       unichars[0] = (c >> 10) + 0xD800;
740       unichars[1] = (c & 0x3FF) + 0xDC00;
742       return 2;
743     }
746 static Boolean
747 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
748                                          FontSymbolicTraits *sym_traits)
750   SInt64 sint64_value;
752   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
753      OS 10.6 when the value is greater than or equal to 1 << 31.  */
754   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
755     {
756       *sym_traits = (FontSymbolicTraits) sint64_value;
758       return true;
759     }
761   return false;
764 static void
765 macfont_store_descriptor_attributes (FontDescriptorRef desc,
766                                      Lisp_Object spec_or_entity)
768   CFStringRef str;
769   CFDictionaryRef dict;
770   CFNumberRef num;
771   CGFloat floatval;
773   str = mac_font_descriptor_copy_attribute (desc,
774                                             MAC_FONT_FAMILY_NAME_ATTRIBUTE);
775   if (str)
776     {
777       ASET (spec_or_entity, FONT_FAMILY_INDEX,
778             macfont_intern_prop_cfstring (str));
779       CFRelease (str);
780     }
781   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
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, MAC_FONT_WEIGHT_TRAIT,
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, MAC_FONT_SLANT_TRAIT,
797             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
798            {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
799             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
800       int i;
802       for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); 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, MAC_FONT_SYMBOLIC_TRAIT);
824       if (num)
825         {
826           FontSymbolicTraits sym_traits;
827           int spacing;
829           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
830           spacing = (sym_traits & MAC_FONT_TRAIT_MONO_SPACE
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 = mac_font_descriptor_copy_attribute (desc, MAC_FONT_SIZE_ATTRIBUTE);
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 (FontDescriptorRef desc, Lisp_Object extra,
848                            FontSymbolicTraits synth_sym_traits)
850   Lisp_Object entity;
851   CFDictionaryRef dict;
852   FontSymbolicTraits 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 = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
863   if (dict)
864     {
865       CFNumberRef num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
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 = mac_font_descriptor_copy_attribute (desc, MAC_FONT_NAME_ATTRIBUTE);
875   font_put_extra (entity, QCfont_entity,
876                   make_save_ptr_int ((void *) name, sym_traits));
877   if (synth_sym_traits & MAC_FONT_TRAIT_ITALIC)
878     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
879                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
880   if (synth_sym_traits & MAC_FONT_TRAIT_BOLD)
881     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
882                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
883   if (synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
884     ASET (entity, FONT_SPACING_INDEX,
885           make_number (FONT_SPACING_SYNTHETIC_MONO));
887   return entity;
890 static CFStringRef
891 macfont_create_family_with_symbol (Lisp_Object symbol)
893   static CFArrayRef families = NULL;
894   CFStringRef result = NULL, family_name;
895   int using_cache_p = 1;
896   CFComparatorFunction family_name_comparator;
898   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
899   if (family_name == NULL)
900     return NULL;
902 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
903 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
904   if (CTFontManagerCompareFontFamilyNames != NULL)
905 #endif
906     {
907       family_name_comparator = CTFontManagerCompareFontFamilyNames;
908     }
909 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
910   else               /* CTFontManagerCompareFontFamilyNames == NULL */
911 #endif
912 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
913 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
914     {
915       family_name_comparator = mac_font_family_compare;
916     }
917 #endif
919   if ((*family_name_comparator) (family_name, CFSTR ("LastResort"), NULL)
920       == kCFCompareEqualTo)
921     result = CFSTR ("LastResort");
922   else
923     while (1)
924       {
925         CFIndex i, count;
927         if (families == NULL)
928           {
929             families = mac_font_create_available_families ();
930             using_cache_p = 0;
931             if (families == NULL)
932               break;
933           }
935         count = CFArrayGetCount (families);
936         i = CFArrayBSearchValues (families, CFRangeMake (0, count),
937                                   (const void *) family_name,
938                                   family_name_comparator, NULL);
939         if (i < count)
940           {
941             CFStringRef name = CFArrayGetValueAtIndex (families, i);
943             if ((*family_name_comparator) (name, family_name, NULL)
944                 == kCFCompareEqualTo)
945               result = CFRetain (name);
946           }
948         if (result || !using_cache_p)
949           break;
950         else
951           {
952             CFRelease (families);
953             families = NULL;
954           }
955       }
957   CFRelease (family_name);
959   return result;
962 #define WIDTH_FRAC_BITS         (4)
963 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
965 struct macfont_metrics
967   unsigned char lbearing_low, rbearing_low;
968   signed lbearing_high : 4, rbearing_high : 4;
969   unsigned char ascent_low, descent_low;
970   signed ascent_high : 4, descent_high : 4;
972   /* These two members are used for fixed-point representation of
973      glyph width.  The `width_int' member is an integer that is
974      closest to the width.  The `width_frac' member is the fractional
975      adjustment representing a value in [-.5, .5], multiplied by
976      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
977      the advance delta for centering instead of the glyph width.  */
978   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
981 #define METRICS_VALUE(metrics, member) \
982   (((metrics)->member##_high << 8) | (metrics)->member##_low)
983 #define METRICS_SET_VALUE(metrics, member, value) \
984   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff; \
985       (metrics)->member##_high = tmp >> 8;} while (0)
987 enum metrics_status
988   {
989     METRICS_INVALID = -1,    /* metrics entry is invalid */
990     METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
991   };
993 #define METRICS_STATUS(metrics) \
994   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
995 #define METRICS_SET_STATUS(metrics, status) \
996   do {METRICS_SET_VALUE (metrics, ascent, 0); \
997       METRICS_SET_VALUE (metrics, descent, status);} while (0)
999 #define METRICS_NCOLS_PER_ROW   (128)
1000 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1001 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1003 static int
1004 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1005                        struct font_metrics *metrics, CGFloat *advance_delta,
1006                        int force_integral_p)
1008   struct macfont_info *macfont_info = (struct macfont_info *) font;
1009   FontRef macfont = macfont_info->macfont;
1010   int row, col;
1011   struct macfont_metrics *cache;
1012   int width;
1014   row = glyph / METRICS_NCOLS_PER_ROW;
1015   col = glyph % METRICS_NCOLS_PER_ROW;
1016   if (row >= macfont_info->metrics_nrows)
1017     {
1018       macfont_info->metrics =
1019         xrealloc (macfont_info->metrics,
1020                   sizeof (struct macfont_metrics *) * (row + 1));
1021       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1022               (sizeof (struct macfont_metrics *)
1023                * (row + 1 - macfont_info->metrics_nrows)));
1024       macfont_info->metrics_nrows = row + 1;
1025     }
1026   if (macfont_info->metrics[row] == NULL)
1027     {
1028       struct macfont_metrics *new;
1029       int i;
1031       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1032       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1033         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1034       macfont_info->metrics[row] = new;
1035     }
1036   cache = macfont_info->metrics[row] + col;
1038   if (METRICS_STATUS (cache) == METRICS_INVALID)
1039     {
1040       CGFloat fwidth;
1042       if (macfont_info->screen_font)
1043         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1044       else
1045         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1047       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1048          advance delta value.  */
1049       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1050         fwidth = (font->pixel_size - fwidth) / 2;
1051       cache->width_int = lround (fwidth);
1052       cache->width_frac = lround ((fwidth - cache->width_int)
1053                                   * WIDTH_FRAC_SCALE);
1054       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1055     }
1056   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1057     width = font->pixel_size;
1058   else
1059     width = cache->width_int;
1061   if (metrics)
1062     {
1063       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1064         {
1065           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1067           if (macfont_info->synthetic_italic_p)
1068             {
1069               /* We assume the members a, b, c, and d in
1070                  synthetic_italic_atfm are non-negative.  */
1071               bounds.origin =
1072                 CGPointApplyAffineTransform (bounds.origin,
1073                                              synthetic_italic_atfm);
1074               bounds.size =
1075                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1076             }
1077           if (macfont_info->synthetic_bold_p)
1078             {
1079               CGFloat d =
1080                 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1082               bounds = CGRectInset (bounds, d, d);
1083             }
1084           switch (macfont_info->spacing)
1085             {
1086             case MACFONT_SPACING_PROPORTIONAL:
1087               bounds.origin.x += - (cache->width_frac
1088                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1089               break;
1090             case MACFONT_SPACING_MONO:
1091               break;
1092             case MACFONT_SPACING_SYNTHETIC_MONO:
1093               bounds.origin.x += (cache->width_int
1094                                   + (cache->width_frac
1095                                      / (CGFloat) WIDTH_FRAC_SCALE));
1096               break;
1097             }
1098           if (bounds.size.width > 0)
1099             {
1100               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1101               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1102                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1103             }
1104           bounds = CGRectIntegral (bounds);
1105           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1106           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1107           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1108           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1109         }
1110       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1111       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1112       metrics->width = width;
1113       metrics->ascent = METRICS_VALUE (cache, ascent);
1114       metrics->descent = METRICS_VALUE (cache, descent);
1115     }
1117   if (advance_delta)
1118     {
1119       switch (macfont_info->spacing)
1120         {
1121         case MACFONT_SPACING_PROPORTIONAL:
1122           *advance_delta = (force_integral_p ? 0
1123                             : - (cache->width_frac
1124                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1125           break;
1126         case MACFONT_SPACING_MONO:
1127           *advance_delta = 0;
1128           break;
1129         case MACFONT_SPACING_SYNTHETIC_MONO:
1130           *advance_delta = (force_integral_p ? cache->width_int
1131                             : (cache->width_int
1132                                + (cache->width_frac
1133                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1134           break;
1135         }
1136     }
1138   return width;
1141 static CFMutableDictionaryRef macfont_cache_dictionary;
1143 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1144    equal to the number of rows that are invalid as BMP (i.e., from
1145    U+D800 to U+DFFF).  */
1146 #define ROW_PERM_OFFSET (8)
1148 /* The number of glyphs that can be stored in a value for a single
1149    entry of CFDictionary.  */
1150 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1152 struct macfont_cache
1154   int reference_count;
1155   CFCharacterSetRef cf_charset;
1156   struct {
1157     /* The cached glyph for a BMP character c is stored in
1158        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1159        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1160     unsigned char row_nkeys_or_perm[256];
1161     CGGlyph **matrix;
1163     /* Number of rows for which the BMP cache is allocated so far.
1164        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1165     int nrows;
1167     /* The cached glyph for a character c is stored as the (c %
1168        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1169        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1170        not stored here if row_nkeys_or_perm[c / 256] >=
1171        ROW_PERM_OFFSET.  */
1172     CFMutableDictionaryRef dictionary;
1173   } glyph;
1175   struct {
1176     /* UVS (Unicode Variation Sequence) subtable data, which is of
1177        type CFDataRef if available.  NULL means it is not initialized
1178        yet.  kCFNull means the subtable is not found and there is no
1179        suitable fallback table for this font.  */
1180     CFTypeRef table;
1182     /* Character collection specifying the destination of the mapping
1183        provided by `table' above.  If `table' is obtained from the UVS
1184        subtable in the font cmap table, then the value of this member
1185        should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING.  */
1186     CharacterCollection collection;
1187   } uvs;
1190 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1191 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1192 static void macfont_release_cache (struct macfont_cache *);
1193 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1194 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1195 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1196 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1197                                           CharacterCollection, CGFontIndex);
1198 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1200 static struct macfont_cache *
1201 macfont_lookup_cache (CFStringRef key)
1203   struct macfont_cache *cache;
1205   if (macfont_cache_dictionary == NULL)
1206     {
1207       macfont_cache_dictionary =
1208         CFDictionaryCreateMutable (NULL, 0,
1209                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1210       cache = NULL;
1211     }
1212   else
1213     cache = ((struct macfont_cache *)
1214              CFDictionaryGetValue (macfont_cache_dictionary, key));
1216   if (cache == NULL)
1217     {
1218       FontRef macfont = mac_font_create_with_name (key, 0);
1220       if (macfont)
1221         {
1222           cache = xzalloc (sizeof (struct macfont_cache));
1223           /* Treat the LastResort font as if it contained glyphs for
1224              all characters.  This may look too rough, but neither
1225              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1226              for this font is correct for non-BMP characters on Mac OS
1227              X 10.5, anyway.  */
1228           if (CFStringCompare (key, CFSTR ("LastResort"), 0)
1229               == kCFCompareEqualTo)
1230             {
1231               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1233               cache->cf_charset =
1234                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1235             }
1236           if (cache->cf_charset == NULL)
1237             cache->cf_charset = mac_font_copy_character_set (macfont);
1238           CFDictionaryAddValue (macfont_cache_dictionary, key,
1239                                 (const void *) cache);
1240           CFRelease (macfont);
1241         }
1242     }
1244   return cache;
1247 static struct macfont_cache *
1248 macfont_retain_cache (struct macfont_cache *cache)
1250   cache->reference_count++;
1252   return cache;
1255 static void
1256 macfont_release_cache (struct macfont_cache *cache)
1258   if (--cache->reference_count == 0)
1259     {
1260       int i;
1262       for (i = 0; i < cache->glyph.nrows; i++)
1263         xfree (cache->glyph.matrix[i]);
1264       xfree (cache->glyph.matrix);
1265       if (cache->glyph.dictionary)
1266         CFRelease (cache->glyph.dictionary);
1267       memset (&cache->glyph, 0, sizeof (cache->glyph));
1268       if (cache->uvs.table)
1269         CFRelease (cache->uvs.table);
1270       memset (&cache->uvs, 0, sizeof (cache->uvs));
1271     }
1274 static CFCharacterSetRef
1275 macfont_get_cf_charset (struct font *font)
1277   struct macfont_info *macfont_info = (struct macfont_info *) font;
1279   return macfont_info->cache->cf_charset;
1282 static CFCharacterSetRef
1283 macfont_get_cf_charset_for_name (CFStringRef name)
1285   struct macfont_cache *cache = macfont_lookup_cache (name);
1287   return cache->cf_charset;
1290 static CGGlyph
1291 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1293   struct macfont_info *macfont_info = (struct macfont_info *) font;
1294   FontRef macfont = macfont_info->macfont;
1295   struct macfont_cache *cache = macfont_info->cache;
1297   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1298     {
1299       int row = c / 256;
1300       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1302       if (nkeys_or_perm < ROW_PERM_OFFSET)
1303         {
1304           UniChar unichars[256], ch;
1305           CGGlyph *glyphs;
1306           int i, len;
1307           int nrows;
1308 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1309           dispatch_queue_t queue;
1310           dispatch_group_t group = NULL;
1311 #else
1312           int nkeys;
1313 #endif
1315           if (row != 0)
1316             {
1317               CFMutableDictionaryRef dictionary;
1318               uintptr_t key, value;
1319               int nshifts;
1320               CGGlyph glyph;
1322               if (cache->glyph.dictionary == NULL)
1323                 cache->glyph.dictionary =
1324                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1325               dictionary = cache->glyph.dictionary;
1326               key = c / NGLYPHS_IN_VALUE;
1327               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1328               value = ((uintptr_t)
1329                        CFDictionaryGetValue (dictionary, (const void *) key));
1330               glyph = (value >> nshifts);
1331               if (glyph)
1332                 return glyph;
1334               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1335                 {
1336                   ch = c;
1337                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1338                                                            &glyph, 1)
1339                       || glyph == 0)
1340                     glyph = kCGFontIndexInvalid;
1342                   if (value == 0)
1343                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1344                   value |= ((uintptr_t) glyph << nshifts);
1345                   CFDictionarySetValue (dictionary, (const void *) key,
1346                                         (const void *) value);
1348                   return glyph;
1349                 }
1351 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1352               queue =
1353                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1354               group = dispatch_group_create ();
1355               dispatch_group_async (group, queue, ^{
1356                   int nkeys;
1357                   uintptr_t key;
1358 #endif
1359                   nkeys = nkeys_or_perm;
1360                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1361                     if (CFDictionaryContainsKey (dictionary,
1362                                                  (const void *) key))
1363                       {
1364                         CFDictionaryRemoveValue (dictionary,
1365                                                  (const void *) key);
1366                         if (--nkeys == 0)
1367                           break;
1368                       }
1369 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1370                 });
1371 #endif
1372             }
1374           len = 0;
1375           for (i = 0; i < 256; i++)
1376             {
1377               ch = row * 256 + i;
1378               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1379                 unichars[len++] = ch;
1380             }
1382           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1383           if (len > 0)
1384             {
1385               mac_font_get_glyphs_for_characters (macfont, unichars,
1386                                                   glyphs, len);
1387               while (i > len)
1388                 {
1389                   int next = unichars[len - 1] % 256;
1391                   while (--i > next)
1392                     glyphs[i] = kCGFontIndexInvalid;
1394                   len--;
1395                   glyphs[i] = glyphs[len];
1396                   if (len == 0)
1397                     break;
1398                 }
1399             }
1400           if (i > len)
1401             while (i-- > 0)
1402               glyphs[i] = kCGFontIndexInvalid;
1404           nrows = cache->glyph.nrows;
1405           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1406           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1407           nrows++;
1408           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1409                                           sizeof (CGGlyph *) * nrows);
1410           cache->glyph.matrix[nrows - 1] = glyphs;
1411           cache->glyph.nrows = nrows;
1413 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1414           if (group)
1415             {
1416               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1417               dispatch_release (group);
1418             }
1419 #endif
1420         }
1422       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1423     }
1424   else
1425     {
1426       uintptr_t key, value;
1427       int nshifts;
1428       CGGlyph glyph;
1430       if (cache->glyph.dictionary == NULL)
1431         cache->glyph.dictionary =
1432           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1433       key = c / NGLYPHS_IN_VALUE;
1434       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1435       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1436                                                 (const void *) key);
1437       glyph = (value >> nshifts);
1438       if (glyph == 0)
1439         {
1440           UniChar unichars[2];
1441           CGGlyph glyphs[2];
1442           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1444           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1445                                                   count))
1446             glyph = glyphs[0];
1447           if (glyph == 0)
1448             glyph = kCGFontIndexInvalid;
1450           value |= ((uintptr_t) glyph << nshifts);
1451           CFDictionarySetValue (cache->glyph.dictionary,
1452                                 (const void *) key, (const void *) value);
1453         }
1455       return glyph;
1456     }
1459 static CGGlyph
1460 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1461                            CGFontIndex cid)
1463   struct macfont_info *macfont_info = (struct macfont_info *) font;
1464   FontRef macfont = macfont_info->macfont;
1466   /* Cache it? */
1467   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1470 static CFDataRef
1471 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1473   struct macfont_info *macfont_info = (struct macfont_info *) font;
1474   FontRef macfont = macfont_info->macfont;
1475   struct macfont_cache *cache = macfont_info->cache;
1476   CFDataRef result = NULL;
1478   if (cache->uvs.table == NULL)
1479     {
1480       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1481       CharacterCollection uvs_collection =
1482         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1484       if (uvs_table == NULL
1485           && mac_font_get_glyph_for_cid (macfont,
1486                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1487                                          6480) != kCGFontIndexInvalid)
1488         {
1489           /* If the glyph for U+4E55 is accessible via its CID 6480,
1490              then we use the Adobe-Japan1 UVS table, which maps a
1491              variation sequence to a CID, as a fallback.  */
1492           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1494           if (mac_uvs_table_adobe_japan1 == NULL)
1495             mac_uvs_table_adobe_japan1 =
1496               CFDataCreateWithBytesNoCopy (NULL,
1497                                            mac_uvs_table_adobe_japan1_bytes,
1498                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1499                                            kCFAllocatorNull);
1500           if (mac_uvs_table_adobe_japan1)
1501             {
1502               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1503               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1504             }
1505         }
1506       if (uvs_table == NULL)
1507         cache->uvs.table = kCFNull;
1508       else
1509         cache->uvs.table = uvs_table;
1510       cache->uvs.collection = uvs_collection;
1511     }
1513   if (cache->uvs.table != kCFNull)
1514     {
1515       result = cache->uvs.table;
1516       *collection = cache->uvs.collection;
1517     }
1519   return result;
1522 static Lisp_Object macfont_get_cache (struct frame *);
1523 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1524 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1525 static Lisp_Object macfont_list_family (struct frame *);
1526 static void macfont_free_entity (Lisp_Object);
1527 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1528 static void macfont_close (struct font *);
1529 static int macfont_has_char (Lisp_Object, int);
1530 static unsigned macfont_encode_char (struct font *, int);
1531 static int macfont_text_extents (struct font *, unsigned int *, int,
1532                                  struct font_metrics *);
1533 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1534 static Lisp_Object macfont_shape (Lisp_Object);
1535 static int macfont_variation_glyphs (struct font *, int c,
1536                                      unsigned variations[256]);
1537 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1539 static struct font_driver macfont_driver =
1540   {
1541     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1542     0,                          /* case insensitive */
1543     macfont_get_cache,
1544     macfont_list,
1545     macfont_match,
1546     macfont_list_family,
1547     macfont_free_entity,
1548     macfont_open,
1549     macfont_close,
1550     NULL,                       /* prepare_face */
1551     NULL,                       /* done_face */
1552     macfont_has_char,
1553     macfont_encode_char,
1554     macfont_text_extents,
1555     macfont_draw,
1556     NULL,                       /* get_bitmap */
1557     NULL,                       /* free_bitmap */
1558     NULL,                       /* get_outline */
1559     NULL,                       /* free_outline */
1560     NULL,                       /* anchor_point */
1561     NULL,                       /* otf_capability */
1562     NULL,                       /* otf_drive */
1563     NULL,                       /* start_for_frame */
1564     NULL,                       /* end_for_frame */
1565     macfont_shape,
1566     NULL,                       /* check */
1567     macfont_variation_glyphs,
1568     macfont_filter_properties,
1569   };
1571 static Lisp_Object
1572 macfont_get_cache (struct frame * f)
1574   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1576   return (dpyinfo->name_list_element);
1579 static int
1580 macfont_get_charset (Lisp_Object registry)
1582   char *str = SSDATA (SYMBOL_NAME (registry));
1583   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1584   Lisp_Object regexp;
1585   int i, j;
1587   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1588     {
1589       if (str[i] == '.')
1590         re[j++] = '\\';
1591       else if (str[i] == '*')
1592         re[j++] = '.';
1593       re[j] = str[i];
1594       if (re[j] == '?')
1595         re[j] = '.';
1596     }
1597   re[j] = '\0';
1598   regexp = make_unibyte_string (re, j);
1599   for (i = 0; cf_charset_table[i].name; i++)
1600     if (fast_c_string_match_ignore_case
1601         (regexp, cf_charset_table[i].name,
1602          strlen (cf_charset_table[i].name)) >= 0)
1603       break;
1604   if (! cf_charset_table[i].name)
1605     return -1;
1606   if (! cf_charset_table[i].cf_charset)
1607     {
1608       int *uniquifier = cf_charset_table[i].uniquifier;
1609       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1610       CFIndex count = 0;
1611       CFStringRef string;
1612       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1614       if (! charset)
1615         return -1;
1616       for (j = 0; uniquifier[j]; j++)
1617         {
1618           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1619                                                         unichars + count);
1620           CFCharacterSetAddCharactersInRange (charset,
1621                                               CFRangeMake (uniquifier[j], 1));
1622         }
1624       string = CFStringCreateWithCharacters (NULL, unichars, count);
1625       if (! string)
1626         {
1627           CFRelease (charset);
1628           return -1;
1629         }
1630       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1631                                                                  charset);
1632       CFRelease (charset);
1633       /* CFCharacterSetCreateWithCharactersInString does not handle
1634          surrogate pairs properly as of Mac OS X 10.5.  */
1635      cf_charset_table[i].cf_charset_string = string;
1636     }
1637   return i;
1640 struct OpenTypeSpec
1642   Lisp_Object script;
1643   unsigned int script_tag, langsys_tag;
1644   int nfeatures[2];
1645   unsigned int *features[2];
1648 #define OTF_SYM_TAG(SYM, TAG)                                   \
1649   do {                                                          \
1650     unsigned char *p = SDATA (SYMBOL_NAME (SYM));               \
1651     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1652   } while (0)
1654 #define OTF_TAG_STR(TAG, P)                     \
1655   do {                                          \
1656     (P)[0] = (char) (TAG >> 24);                \
1657     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1658     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1659     (P)[3] = (char) (TAG & 0xFF);               \
1660     (P)[4] = '\0';                              \
1661   } while (0)
1663 static struct OpenTypeSpec *
1664 macfont_get_open_type_spec (Lisp_Object otf_spec)
1666   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1667   Lisp_Object val;
1668   int i, j;
1669   bool negative;
1671   if (! spec)
1672     return NULL;
1673   spec->script = XCAR (otf_spec);
1674   if (! NILP (spec->script))
1675     {
1676       OTF_SYM_TAG (spec->script, spec->script_tag);
1677       val = assq_no_quit (spec->script, Votf_script_alist);
1678       if (CONSP (val) && SYMBOLP (XCDR (val)))
1679         spec->script = XCDR (val);
1680       else
1681         spec->script = Qnil;
1682     }
1683   else
1684     spec->script_tag = 0x44464C54;      /* "DFLT" */
1685   otf_spec = XCDR (otf_spec);
1686   spec->langsys_tag = 0;
1687   if (! NILP (otf_spec))
1688     {
1689       val = XCAR (otf_spec);
1690       if (! NILP (val))
1691         OTF_SYM_TAG (val, spec->langsys_tag);
1692       otf_spec = XCDR (otf_spec);
1693     }
1694   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1695   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1696     {
1697       Lisp_Object len;
1699       val = XCAR (otf_spec);
1700       if (NILP (val))
1701         continue;
1702       len = Flength (val);
1703       spec->features[i] =
1704         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1705          ? 0
1706          : malloc (XINT (len) * sizeof *spec->features[i]));
1707       if (! spec->features[i])
1708         {
1709           if (i > 0 && spec->features[0])
1710             free (spec->features[0]);
1711           free (spec);
1712           return NULL;
1713         }
1714       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1715         {
1716           if (NILP (XCAR (val)))
1717             negative = 1;
1718           else
1719             {
1720               unsigned int tag;
1722               OTF_SYM_TAG (XCAR (val), tag);
1723               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1724             }
1725         }
1726       spec->nfeatures[i] = j;
1727     }
1728   return spec;
1731 static CFMutableDictionaryRef
1732 macfont_create_attributes_with_spec (Lisp_Object spec)
1734   Lisp_Object tmp, extra;
1735   CFMutableArrayRef langarray = NULL;
1736   CFCharacterSetRef charset = NULL;
1737   CFStringRef charset_string = NULL;
1738   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1739   Lisp_Object script = Qnil;
1740   Lisp_Object registry;
1741   int cf_charset_idx, i;
1742   struct OpenTypeSpec *otspec = NULL;
1743   struct {
1744     enum font_property_index index;
1745     CFStringRef trait;
1746     CGPoint points[6];
1747   } numeric_traits[] =
1748       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1749         {{-0.4, 50},            /* light */
1750          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1751          {0, 100},              /* normal */
1752          {0.24, 140},           /* (semi-bold + normal) / 2 */
1753          {0.4, 200},            /* bold */
1754          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1755        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1756         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1757        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1758         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1760   registry = AREF (spec, FONT_REGISTRY_INDEX);
1761   if (NILP (registry)
1762       || EQ (registry, Qascii_0)
1763       || EQ (registry, Qiso10646_1)
1764       || EQ (registry, Qunicode_bmp))
1765     cf_charset_idx = -1;
1766   else
1767     {
1768       CFStringRef lang;
1770       cf_charset_idx = macfont_get_charset (registry);
1771       if (cf_charset_idx < 0)
1772         goto err;
1773       charset = cf_charset_table[cf_charset_idx].cf_charset;
1774       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1775       lang = cf_charset_table[cf_charset_idx].lang;
1776       if (lang)
1777         {
1778           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1779           if (! langarray)
1780             goto err;
1781           CFArrayAppendValue (langarray, lang);
1782         }
1783     }
1785   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1786        CONSP (extra); extra = XCDR (extra))
1787     {
1788       Lisp_Object key, val;
1790       tmp = XCAR (extra);
1791       key = XCAR (tmp), val = XCDR (tmp);
1792       if (EQ (key, QClang))
1793         {
1794           if (! langarray)
1795             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1796           if (! langarray)
1797             goto err;
1798           if (SYMBOLP (val))
1799             val = list1 (val);
1800           for (; CONSP (val); val = XCDR (val))
1801             if (SYMBOLP (XCAR (val)))
1802               {
1803                 CFStringRef lang =
1804                   cfstring_create_with_string_noencode (SYMBOL_NAME
1805                                                         (XCAR (val)));
1807                 if (lang == NULL)
1808                   goto err;
1809                 CFArrayAppendValue (langarray, lang);
1810                 CFRelease (lang);
1811               }
1812         }
1813       else if (EQ (key, QCotf))
1814         {
1815           otspec = macfont_get_open_type_spec (val);
1816           if (! otspec)
1817             goto err;
1818           script = otspec->script;
1819         }
1820       else if (EQ (key, QCscript))
1821         script = val;
1822     }
1824   if (! NILP (script) && ! charset)
1825     {
1826       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1828       if (CONSP (chars) && CONSP (CDR (chars)))
1829         {
1830           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1831           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1833           if (! string || !cs)
1834             {
1835               if (string)
1836                 CFRelease (string);
1837               else if (cs)
1838                 CFRelease (cs);
1839               goto err;
1840             }
1841           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1842             if (CHARACTERP (XCAR (chars)))
1843               {
1844                 UniChar unichars[2];
1845                 CFIndex count =
1846                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1847                                                        unichars);
1848                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1850                 CFStringAppendCharacters (string, unichars, count);
1851                 CFCharacterSetAddCharactersInRange (cs, range);
1852               }
1853           charset = cs;
1854           /* CFCharacterSetCreateWithCharactersInString does not
1855              handle surrogate pairs properly as of Mac OS X 10.5.  */
1856           charset_string = string;
1857         }
1858     }
1860   attributes = CFDictionaryCreateMutable (NULL, 0,
1861                                           &kCFTypeDictionaryKeyCallBacks,
1862                                           &kCFTypeDictionaryValueCallBacks);
1863   if (! attributes)
1864     goto err;
1866   tmp = AREF (spec, FONT_FAMILY_INDEX);
1867   if (SYMBOLP (tmp) && ! NILP (tmp))
1868     {
1869       CFStringRef family = macfont_create_family_with_symbol (tmp);
1871       if (! family)
1872         goto err;
1873       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1874                             family);
1875       CFRelease (family);
1876     }
1878   traits = CFDictionaryCreateMutable (NULL, 4,
1879                                       &kCFTypeDictionaryKeyCallBacks,
1880                                       &kCFTypeDictionaryValueCallBacks);
1881   if (! traits)
1882     goto err;
1884   for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); i++)
1885     {
1886       tmp = AREF (spec, numeric_traits[i].index);
1887       if (INTEGERP (tmp))
1888         {
1889           CGPoint *point = numeric_traits[i].points;
1890           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1891           CFNumberRef num;
1893           while (point->y < floatval)
1894             point++;
1895           if (point == numeric_traits[i].points)
1896             point++;
1897           else if (point->y == CGFLOAT_MAX)
1898             point--;
1899           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1900                                        * ((point->x - (point - 1)->x)
1901                                           / (point->y - (point - 1)->y)));
1902           if (floatval > 1.0)
1903             floatval = 1.0;
1904           else if (floatval < -1.0)
1905             floatval = -1.0;
1906           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1907           if (! num)
1908             goto err;
1909           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1910           CFRelease (num);
1911         }
1912     }
1913   if (CFDictionaryGetCount (traits))
1914     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1916   if (charset)
1917     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1918                           charset);
1919   if (charset_string)
1920     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1921                           charset_string);
1922   if (langarray)
1923     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1925   goto finish;
1927  err:
1928   if (attributes)
1929     {
1930       CFRelease (attributes);
1931       attributes = NULL;
1932     }
1934  finish:
1935   if (langarray) CFRelease (langarray);
1936   if (charset && cf_charset_idx < 0) CFRelease (charset);
1937   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1938   if (traits) CFRelease (traits);
1939   if (otspec)
1940     {
1941       if (otspec->nfeatures[0] > 0)
1942         free (otspec->features[0]);
1943       if (otspec->nfeatures[1] > 0)
1944         free (otspec->features[1]);
1945       free (otspec);
1946     }
1948   return attributes;
1951 static Boolean
1952 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1953                                           CFCharacterSetRef charset,
1954                                           Lisp_Object chars,
1955                                           CFArrayRef languages)
1957   Boolean result = true;
1959   if (charset || VECTORP (chars))
1960     {
1961       CFCharacterSetRef desc_charset =
1962         mac_font_descriptor_copy_attribute (desc,
1963                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1965       if (desc_charset == NULL)
1966         result = false;
1967       else
1968         {
1969           if (charset)
1970             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1971           else                  /* VECTORP (chars) */
1972             {
1973               ptrdiff_t j;
1975               for (j = 0; j < ASIZE (chars); j++)
1976                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
1977                     && CFCharacterSetIsLongCharacterMember (desc_charset,
1978                                                             XFASTINT (AREF (chars, j))))
1979                   break;
1980               if (j == ASIZE (chars))
1981                 result = false;
1982             }
1983           CFRelease (desc_charset);
1984         }
1985     }
1986   if (result && languages)
1987     result = mac_font_descriptor_supports_languages (desc, languages);
1989   return result;
1992 static CFIndex
1993 macfont_closest_traits_index (CFArrayRef traits_array,
1994                               FontSymbolicTraits target)
1996   CFIndex i, result = -1, count = CFArrayGetCount (traits_array);
1997   int min_distance = (1 << 3);
1999   for (i = 0; i < count; i++)
2000     {
2001       FontSymbolicTraits traits, diff;
2002       int distance = 0;
2004       traits = ((FontSymbolicTraits) (uintptr_t)
2005                 CFArrayGetValueAtIndex (traits_array, i));
2006       diff = (target ^ traits);
2007       /* We prefer synthetic bold of italic to synthetic italic of
2008          bold when both bold and italic are available but bold-italic
2009          is not available.  */
2010       if (diff & MAC_FONT_TRAIT_BOLD)
2011         distance |= (1 << 0);
2012       if (diff & MAC_FONT_TRAIT_ITALIC)
2013         distance |= (1 << 1);
2014       if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2015         distance |= (1 << 2);
2016       if (distance < min_distance)
2017         {
2018           min_distance = distance;
2019           result = i;
2020         }
2021     }
2023   return result;
2026 static Lisp_Object
2027 macfont_list (struct frame *f, Lisp_Object spec)
2029   Lisp_Object val = Qnil, family, extra;
2030   int i, n;
2031   CFStringRef family_name = NULL;
2032   CFMutableDictionaryRef attributes = NULL, traits;
2033   Lisp_Object chars = Qnil;
2034   int spacing = -1;
2035   FontSymbolicTraits synth_sym_traits = 0;
2036   CFArrayRef families;
2037   CFIndex families_count;
2038   CFCharacterSetRef charset = NULL;
2039   CFArrayRef languages = NULL;
2041   block_input ();
2043   family = AREF (spec, FONT_FAMILY_INDEX);
2044   if (! NILP (family))
2045     {
2046       family_name = macfont_create_family_with_symbol (family);
2047       if (family_name == NULL)
2048         goto finish;
2049     }
2051   attributes = macfont_create_attributes_with_spec (spec);
2052   if (! attributes)
2053     goto finish;
2055   charset = ((CFCharacterSetRef)
2056              CFDictionaryGetValue (attributes,
2057                                    MAC_FONT_CHARACTER_SET_ATTRIBUTE));
2058   if (charset)
2059     {
2060       CFRetain (charset);
2061       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2062     }
2063   else
2064     {
2065       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2066       if (! NILP (val))
2067         {
2068           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2069           if (CONSP (val) && VECTORP (XCDR (val)))
2070             chars = XCDR (val);
2071         }
2072       val = Qnil;
2073     }
2075   languages = ((CFArrayRef)
2076                CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE));
2077   if (languages)
2078     {
2079       CFRetain (languages);
2080       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2081     }
2083   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2084     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2086   traits = ((CFMutableDictionaryRef)
2087             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2089   n = FONT_SLANT_NUMERIC (spec);
2090   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2091     {
2092       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2093       if (traits)
2094         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2095     }
2097   n = FONT_WEIGHT_NUMERIC (spec);
2098   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2099     {
2100       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2101       if (traits)
2102         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2103     }
2105   if (languages
2106       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2107     {
2108       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2110       if (CFStringHasPrefix (language, CFSTR ("ja"))
2111           || CFStringHasPrefix (language, CFSTR ("ko"))
2112           || CFStringHasPrefix (language, CFSTR ("zh")))
2113         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2114     }
2116   /* Create array of families.  */
2117   if (family_name)
2118     families = CFArrayCreate (NULL, (const void **) &family_name,
2119                               1, &kCFTypeArrayCallBacks);
2120   else
2121     {
2122       CFStringRef pref_family;
2123       CFIndex families_count, pref_family_index = -1;
2125       families = mac_font_create_available_families ();
2126       if (families == NULL)
2127         goto err;
2129       families_count = CFArrayGetCount (families);
2131       /* Move preferred family to the front if exists.  */
2132       pref_family =
2133         mac_font_create_preferred_family_for_attributes (attributes);
2134       if (pref_family)
2135         {
2136           pref_family_index =
2137             CFArrayGetFirstIndexOfValue (families,
2138                                          CFRangeMake (0, families_count),
2139                                          pref_family);
2140           CFRelease (pref_family);
2141         }
2142       if (pref_family_index > 0)
2143         {
2144           CFMutableArrayRef mutable_families =
2145             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2147           if (mutable_families)
2148             {
2149               CFArrayAppendValue (mutable_families,
2150                                   CFArrayGetValueAtIndex (families,
2151                                                           pref_family_index));
2152               CFArrayAppendArray (mutable_families, families,
2153                                   CFRangeMake (0, pref_family_index));
2154               if (pref_family_index + 1 < families_count)
2155                 CFArrayAppendArray (mutable_families, families,
2156                                     CFRangeMake (pref_family_index + 1,
2157                                                  families_count
2158                                                  - (pref_family_index + 1)));
2159               CFRelease (families);
2160               families = mutable_families;
2161             }
2162         }
2163     }
2165   val = Qnil;
2166   extra = AREF (spec, FONT_EXTRA_INDEX);
2167   families_count = CFArrayGetCount (families);
2168   for (i = 0; i < families_count; i++)
2169     {
2170       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2171       FontDescriptorRef pat_desc;
2172       CFArrayRef descs;
2173       CFIndex descs_count;
2174       CFMutableArrayRef filtered_descs, traits_array;
2175       Lisp_Object entity;
2176       int j;
2178       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2179                             family_name);
2180       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2181       if (! pat_desc)
2182         goto err;
2184       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2185          10.7 returns NULL if pat_desc represents the LastResort font.
2186          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2187          trailing "s") for such a font.  */
2188       if (CFStringCompare (family_name, CFSTR ("LastResort"), 0)
2189           != kCFCompareEqualTo)
2190         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2191                                                                       NULL);
2192       else
2193         {
2194           FontDescriptorRef lr_desc =
2195             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2196                                                                  NULL);
2197           if (lr_desc)
2198             {
2199               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2200                                      &kCFTypeArrayCallBacks);
2201               CFRelease (lr_desc);
2202             }
2203           else
2204             descs = NULL;
2205         }
2206       CFRelease (pat_desc);
2207       if (! descs)
2208         goto err;
2210       descs_count = CFArrayGetCount (descs);
2211       if (descs_count == 0
2212           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2213                                                         charset, chars,
2214                                                         languages))
2215         {
2216           CFRelease (descs);
2217           continue;
2218         }
2220       filtered_descs =
2221         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2222       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2223       for (j = 0; j < descs_count; j++)
2224         {
2225           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2226           CFDictionaryRef dict;
2227           CFNumberRef num;
2228           FontSymbolicTraits sym_traits;
2230           dict = mac_font_descriptor_copy_attribute (desc,
2231                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2232           if (dict == NULL)
2233             continue;
2235           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2236           CFRelease (dict);
2237           if (num == NULL
2238               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2239             continue;
2241           if (spacing >= 0
2242               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2243               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2244                   != (spacing >= FONT_SPACING_MONO)))
2245             continue;
2247           /* Don't use a color bitmap font unless its family is
2248              explicitly specified.  */
2249           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2250             continue;
2252           if (j > 0
2253               && !macfont_supports_charset_and_languages_p (desc, charset,
2254                                                             chars, languages))
2255             continue;
2257           CFArrayAppendValue (filtered_descs, desc);
2258           CFArrayAppendValue (traits_array,
2259                               (const void *) (uintptr_t) sym_traits);
2260         }
2262       CFRelease (descs);
2263       descs = filtered_descs;
2264       descs_count = CFArrayGetCount (descs);
2266       for (j = 0; j < descs_count; j++)
2267         {
2268           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2269           FontSymbolicTraits sym_traits =
2270             ((FontSymbolicTraits) (uintptr_t)
2271              CFArrayGetValueAtIndex (traits_array, j));
2272           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2274           mask_min = ((synth_sym_traits ^ sym_traits)
2275                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2276           if (FONT_SLANT_NUMERIC (spec) < 0)
2277             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2278           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2279             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2281           mask_max = (synth_sym_traits & ~sym_traits);
2282           /* Synthetic bold does not work for bitmap-only fonts on Mac
2283              OS X 10.6.  */
2284           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2285             {
2286               CFNumberRef format =
2287                 mac_font_descriptor_copy_attribute (desc,
2288                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2290               if (format)
2291                 {
2292                   uint32_t format_val;
2294                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2295                                         &format_val)
2296                       && format_val == MAC_FONT_FORMAT_BITMAP)
2297                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2298                 }
2299             }
2300           if (spacing >= 0)
2301             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2303           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2304                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2305                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2306             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2307                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2308                  bmask += MAC_FONT_TRAIT_BOLD)
2309               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2310                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2311                    imask += MAC_FONT_TRAIT_ITALIC)
2312                 {
2313                   FontSymbolicTraits synth = (imask | bmask | mmask);
2315                   if (synth == 0
2316                       || j == macfont_closest_traits_index (traits_array,
2317                                                             (sym_traits | synth)))
2318                     {
2319                       entity = macfont_descriptor_entity (desc, extra, synth);
2320                       if (! NILP (entity))
2321                         val = Fcons (entity, val);
2322                     }
2323                 }
2324         }
2326       CFRelease (traits_array);
2327       CFRelease (descs);
2328     }
2330   CFRelease (families);
2331   val = Fnreverse (val);
2332   goto finish;
2333  err:
2334   val = Qnil;
2336  finish:
2337   FONT_ADD_LOG ("macfont-list", spec, val);
2338   if (charset) CFRelease (charset);
2339   if (languages) CFRelease (languages);
2340   if (attributes) CFRelease (attributes);
2341   if (family_name) CFRelease (family_name);
2343   unblock_input ();
2345   return val;
2348 static Lisp_Object
2349 macfont_match (struct frame * frame, Lisp_Object spec)
2351   Lisp_Object entity = Qnil;
2352   CFMutableDictionaryRef attributes;
2353   FontDescriptorRef pat_desc = NULL, desc = NULL;
2355   block_input ();
2357   attributes = macfont_create_attributes_with_spec (spec);
2358   if (attributes)
2359     {
2360       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2361       CFRelease (attributes);
2362     }
2363   if (pat_desc)
2364     {
2365       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2366                                                                   NULL);
2367       CFRelease (pat_desc);
2368     }
2369   if (desc)
2370     {
2371       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2372                                           0);
2373       CFRelease (desc);
2374     }
2375   unblock_input ();
2377   FONT_ADD_LOG ("macfont-match", spec, entity);
2378   return entity;
2381 static Lisp_Object
2382 macfont_list_family (struct frame *frame)
2384   Lisp_Object list = Qnil;
2385   CFArrayRef families;
2387   block_input ();
2389   families = mac_font_create_available_families ();
2390   if (families)
2391     {
2392       CFIndex i, count = CFArrayGetCount (families);
2394       for (i = 0; i < count; i++)
2395         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2396       CFRelease (families);
2397     }
2399   unblock_input ();
2401   return list;
2404 static void
2405 macfont_free_entity (Lisp_Object entity)
2407   Lisp_Object val = assq_no_quit (QCfont_entity,
2408                                   AREF (entity, FONT_EXTRA_INDEX));
2409   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2411   block_input ();
2412   CFRelease (name);
2413   unblock_input ();
2416 static Lisp_Object
2417 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2419   Lisp_Object val, font_object;
2420   CFStringRef font_name;
2421   struct macfont_info *macfont_info = NULL;
2422   struct font *font;
2423   int size;
2424   FontRef macfont;
2425   FontSymbolicTraits sym_traits;
2426   char name[256];
2427   int len, i, total_width;
2428   CGGlyph glyph;
2429   CGFloat ascent, descent, leading;
2431   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2432   if (! CONSP (val)
2433       || XTYPE (XCDR (val)) != Lisp_Misc
2434       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2435     return Qnil;
2436   font_name = XSAVE_POINTER (XCDR (val), 0);
2437   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2439   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2440   if (size == 0)
2441     size = pixel_size;
2443   block_input ();
2444   macfont = mac_font_create_with_name (font_name, size);
2445   if (macfont)
2446     {
2447       int fontsize = (int) [((NSFont *) macfont) pointSize];
2448       if (fontsize != size) size = fontsize;
2449     }
2450   unblock_input ();
2451   if (! macfont)
2452     return Qnil;
2454   font_object = font_make_object (VECSIZE (struct macfont_info), entity, size);
2455   ASET (font_object, FONT_TYPE_INDEX, macfont_driver.type);
2456   len = font_unparse_xlfd (entity, size, name, 256);
2457   if (len > 0)
2458     ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
2459   len = font_unparse_fcname (entity, size, name, 256);
2460   if (len > 0)
2461     ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
2462   else
2463     ASET (font_object, FONT_FULLNAME_INDEX,
2464           AREF (font_object, FONT_NAME_INDEX));
2465   font = XFONT_OBJECT (font_object);
2466   font->pixel_size = size;
2467   font->driver = &macfont_driver;
2468   font->encoding_charset = font->repertory_charset = -1;
2470   block_input ();
2472   macfont_info = (struct macfont_info *) font;
2473   macfont_info->macfont = macfont;
2474   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2476   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2477   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2478     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2479                                                                   size);
2480   else
2481     macfont_info->screen_font = NULL;
2482   macfont_info->cache = macfont_lookup_cache (font_name);
2483   macfont_retain_cache (macfont_info->cache);
2484   macfont_info->metrics = NULL;
2485   macfont_info->metrics_nrows = 0;
2486   macfont_info->synthetic_italic_p = 0;
2487   macfont_info->synthetic_bold_p = 0;
2488   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2489   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2490   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2491       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2492     macfont_info->synthetic_italic_p = 1;
2493   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2494       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2495     macfont_info->synthetic_bold_p = 1;
2496   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2497     macfont_info->spacing = MACFONT_SPACING_MONO;
2498   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2499            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2500                == FONT_SPACING_SYNTHETIC_MONO))
2501     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2502   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2503     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2504   else
2505     {
2506       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2507       if (CONSP (val))
2508         macfont_info->antialias =
2509           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2510     }
2511   macfont_info->color_bitmap_p = 0;
2512   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2513     macfont_info->color_bitmap_p = 1;
2515   glyph = macfont_get_glyph_for_character (font, ' ');
2516   if (glyph != kCGFontIndexInvalid)
2517     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2518   else
2519     /* dirty workaround */
2520     font->space_width = pixel_size;
2522   total_width = font->space_width;
2523   for (i = 1; i < 95; i++)
2524     {
2525       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2526       if (glyph == kCGFontIndexInvalid)
2527         break;
2528       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2529     }
2530   if (i == 95)
2531     font->average_width = total_width / 95;
2532   else
2533     font->average_width = font->space_width; /* XXX */
2535   if (!(macfont_info->screen_font
2536         && mac_screen_font_get_metrics (macfont_info->screen_font,
2537                                         &ascent, &descent, &leading)))
2538     {
2539       CFStringRef family_name;
2541       ascent = mac_font_get_ascent (macfont);
2542       descent = mac_font_get_descent (macfont);
2543       leading = mac_font_get_leading (macfont);
2544       /* AppKit and WebKit do some adjustment to the heights of
2545          Courier, Helvetica, and Times.  */
2546       family_name = mac_font_copy_family_name (macfont);
2547       if (family_name)
2548         {
2549           if ((CFStringCompare (family_name, CFSTR ("Courier"), 0)
2550                == kCFCompareEqualTo)
2551               || (CFStringCompare (family_name, CFSTR ("Helvetica"), 0)
2552                   == kCFCompareEqualTo)
2553               || (CFStringCompare (family_name, CFSTR ("Times"), 0)
2554                   == kCFCompareEqualTo))
2555             ascent += (ascent + descent) * .15f;
2556           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2557             {
2558               leading *= .25f;
2559               ascent += leading;
2560             }
2561           CFRelease (family_name);
2562         }
2563     }
2564   font->ascent = ascent + 0.5f;
2565   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2566   if (CONSP (val) && !NILP (XCDR (val)))
2567     font->descent = descent + 0.5f;
2568   else
2569     font->descent = descent + leading + 0.5f;
2570   font->height = font->ascent + font->descent;
2572   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2573   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2575   unblock_input ();
2577   /* Unfortunately Xft doesn't provide a way to get minimum char
2578      width.  So, we use space_width instead.  */
2579   font->min_width = font->max_width = font->space_width; /* XXX */
2581   font->baseline_offset = 0;
2582   font->relative_compose = 0;
2583   font->default_ascent = 0;
2584   font->vertical_centering = 0;
2586   return font_object;
2589 static void
2590 macfont_close (struct font *font)
2592   struct macfont_info *macfont_info = (struct macfont_info *) font;
2594   if (macfont_info->cache)
2595     {
2596       int i;
2598       block_input ();
2599       CFRelease (macfont_info->macfont);
2600       CGFontRelease (macfont_info->cgfont);
2601       if (macfont_info->screen_font)
2602         CFRelease (macfont_info->screen_font);
2603       macfont_release_cache (macfont_info->cache);
2604       macfont_info->cache = NULL;
2605       for (i = 0; i < macfont_info->metrics_nrows; i++)
2606         if (macfont_info->metrics[i])
2607           xfree (macfont_info->metrics[i]);
2608       if (macfont_info->metrics)
2609         xfree (macfont_info->metrics);
2610       unblock_input ();
2611     }
2614 static int
2615 macfont_has_char (Lisp_Object font, int c)
2617   int result;
2618   CFCharacterSetRef charset;
2620   block_input ();
2621   if (FONT_ENTITY_P (font))
2622     {
2623       Lisp_Object val;
2624       CFStringRef name;
2626       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2627       val = XCDR (val);
2628       name = XSAVE_POINTER (val, 0);
2629       charset = macfont_get_cf_charset_for_name (name);
2630     }
2631   else
2632     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2634   result = CFCharacterSetIsLongCharacterMember (charset, c);
2635   unblock_input ();
2637   return result;
2640 static unsigned
2641 macfont_encode_char (struct font *font, int c)
2643   struct macfont_info *macfont_info = (struct macfont_info *) font;
2644   CGGlyph glyph;
2646   block_input ();
2647   glyph = macfont_get_glyph_for_character (font, c);
2648   unblock_input ();
2650   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2653 static int
2654 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2655                       struct font_metrics *metrics)
2657   int width, i;
2659   block_input ();
2660   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2661   for (i = 1; i < nglyphs; i++)
2662     {
2663       struct font_metrics m;
2664       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2665                                      NULL, 0);
2667       if (metrics)
2668         {
2669           if (width + m.lbearing < metrics->lbearing)
2670             metrics->lbearing = width + m.lbearing;
2671           if (width + m.rbearing > metrics->rbearing)
2672             metrics->rbearing = width + m.rbearing;
2673           if (m.ascent > metrics->ascent)
2674             metrics->ascent = m.ascent;
2675           if (m.descent > metrics->descent)
2676             metrics->descent = m.descent;
2677         }
2678       width += w;
2679     }
2680   unblock_input ();
2682   if (metrics)
2683     metrics->width = width;
2685   return width;
2688 static int
2689 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2690               bool with_background)
2692   struct frame * f = s->f;
2693   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2694   FontRef macfont = macfont_info->macfont;
2695   CGContextRef context;
2696   BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2697   int end = isComposite ? s->cmp_to : s->nchars;
2698   int len = end - s->cmp_from;
2699   int i;
2701   block_input ();
2703   context = [[NSGraphicsContext currentContext] graphicsPort];
2704   CGContextSaveGState (context);
2706 #if 0
2707   if (s->num_clips > 0)
2708     {
2709       CGRect clips[2];
2711       for (i = 0; i < s->num_clips; i++)
2712         clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2713                                   s->clip[i].right - s->clip[i].left,
2714                                   s->clip[i].bottom - s->clip[i].top);
2715       CGContextClipToRects (context, clips, s->num_clips);
2716     }
2717 #endif
2719   if (with_background)
2720     {
2721       CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, s);
2722       CGContextFillRect (context,
2723                          CGRectMake (x, y,
2724                                      s->width, FONT_HEIGHT (s->font)));
2725     }
2727   if (macfont_info->cgfont)
2728     {
2729       CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2730       CGPoint *positions = alloca (sizeof (CGPoint) * len);
2731       CGFloat total_width = 0;
2732       CGFloat font_size = mac_font_get_size (macfont);
2733       CGAffineTransform atfm;
2734       CGFloat advance_delta = 0;
2735       int y_draw = -s->ybase;
2736       int no_antialias_p =
2737         (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2738          || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2739              && font_size <= macfont_antialias_threshold));
2741       for (i = 0; i < len; i++)
2742         {
2743           int width;
2745           glyphs[i] = *(s->char2b + s->cmp_from + i);
2746           width = (s->padding_p ? 1
2747                    : macfont_glyph_extents (s->font, glyphs[i],
2748                                             NULL, &advance_delta,
2749                                             no_antialias_p));
2750           positions[i].x = total_width + advance_delta;
2751           positions[i].y = 0;
2752           total_width += width;
2753         }
2755       CGContextScaleCTM (context, 1, -1);
2756       CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, s);
2757       if (macfont_info->synthetic_italic_p)
2758         atfm = synthetic_italic_atfm;
2759       else
2760         atfm = CGAffineTransformIdentity;
2761       if (macfont_info->synthetic_bold_p)
2762         {
2763           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2764           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2765           CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, s);
2766         }
2767       if (no_antialias_p)
2768         CGContextSetShouldAntialias (context, false);
2770       CGContextSetTextMatrix (context, atfm);
2771       CGContextSetTextPosition (context, x, y_draw);
2773 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2774       if (macfont_info->color_bitmap_p
2775 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2776           && CTFontDrawGlyphs != NULL
2777 #endif
2778           )
2779         {
2780           if (len > 0)
2781             {
2782               CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2783             }
2784         }
2785       else
2786 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2787         {
2788           CGContextSetFont (context, macfont_info->cgfont);
2789           CGContextSetFontSize (context, font_size);
2790           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2791         }
2792     }
2794   CGContextRestoreGState (context);
2796   unblock_input ();
2798   return len;
2801 Lisp_Object
2802 macfont_shape (Lisp_Object lgstring)
2804   struct font *font;
2805   struct macfont_info *macfont_info;
2806   FontRef macfont;
2807   ptrdiff_t glyph_len, len, i, j;
2808   CFIndex nonbmp_len;
2809   UniChar *unichars;
2810   CFIndex *nonbmp_indices;
2811   CFStringRef string;
2812   CFIndex used = 0;
2813   struct mac_glyph_layout *glyph_layouts;
2815   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2816   macfont_info = (struct macfont_info *) font;
2817   macfont = macfont_info->macfont;
2819   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2820   nonbmp_len = 0;
2821   for (i = 0; i < glyph_len; i++)
2822     {
2823       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2825       if (NILP (lglyph))
2826         break;
2827       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2828         nonbmp_len++;
2829     }
2831   len = i;
2833   if (INT_MAX / 2 < len)
2834     memory_full (SIZE_MAX);
2836   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2837   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2838   for (i = j = 0; i < len; i++)
2839     {
2840       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2842       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2843         {
2844           nonbmp_indices[j] = i + j;
2845           j++;
2846         }
2847     }
2848   nonbmp_indices[j] = len + j;  /* sentinel */
2850   block_input ();
2852   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2853                                                kCFAllocatorNull);
2854   if (string)
2855     {
2856       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2857       if (macfont_info->screen_font)
2858         used = mac_screen_font_shape (macfont_info->screen_font, string,
2859                                       glyph_layouts, glyph_len);
2860       else
2861         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2862       CFRelease (string);
2863     }
2865   unblock_input ();
2867   if (used == 0)
2868     return Qnil;
2870   block_input ();
2872   for (i = 0; i < used; i++)
2873     {
2874       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2875       struct mac_glyph_layout *gl = glyph_layouts + i;
2876       EMACS_INT from, to;
2877       struct font_metrics metrics;
2878       int xoff, yoff, wadjust;
2880       if (NILP (lglyph))
2881         {
2882           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2883           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2884         }
2886       from = gl->comp_range.location;
2887       /* Convert UTF-16 index to UTF-32.  */
2888       j = 0;
2889       while (nonbmp_indices[j] < from)
2890         j++;
2891       from -= j;
2892       LGLYPH_SET_FROM (lglyph, from);
2894       to = gl->comp_range.location + gl->comp_range.length;
2895       /* Convert UTF-16 index to UTF-32.  */
2896       while (nonbmp_indices[j] < to)
2897         j++;
2898       to -= j;
2899       LGLYPH_SET_TO (lglyph, to - 1);
2901       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2902          the composition is trivial.  */
2903       {
2904         UTF32Char c;
2906         if (unichars[gl->string_index] >= 0xD800
2907             && unichars[gl->string_index] < 0xDC00)
2908           c = (((unichars[gl->string_index] - 0xD800) << 10)
2909                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2910         else
2911           c = unichars[gl->string_index];
2912         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2913           c = 0;
2914         LGLYPH_SET_CHAR (lglyph, c);
2915       }
2917       {
2918         unsigned long cc = gl->glyph_id;
2919         LGLYPH_SET_CODE (lglyph, cc);
2920       }
2922       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2923       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2924       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2925       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2926       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2927       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2929       xoff = lround (gl->advance_delta);
2930       yoff = lround (- gl->baseline_delta);
2931       wadjust = lround (gl->advance);
2932       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2933         {
2934           Lisp_Object vec;
2936           vec = Fmake_vector (make_number (3), Qnil);
2937           ASET (vec, 0, make_number (xoff));
2938           ASET (vec, 1, make_number (yoff));
2939           ASET (vec, 2, make_number (wadjust));
2940           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2941         }
2942     }
2944   unblock_input ();
2946   return make_number (used);
2949 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2950 typedef UInt8 UINT24[3];
2952 #pragma pack(push, 1)
2953 struct variation_selector_record
2955   UINT24 var_selector;
2956   UInt32 default_uvs_offset, non_default_uvs_offset;
2958 struct uvs_table
2960   UInt16 format;
2961   UInt32 length, num_var_selector_records;
2962   struct variation_selector_record variation_selector_records[1];
2964 #define SIZEOF_UVS_TABLE_HEADER \
2965   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2967 struct unicode_value_range
2969   UINT24 start_unicode_value;
2970   UInt8 additional_count;
2972 struct default_uvs_table {
2973   UInt32 num_unicode_value_ranges;
2974   struct unicode_value_range unicode_value_ranges[1];
2976 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
2977   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2979 struct uvs_mapping
2981   UINT24 unicode_value;
2982   UInt16 glyph_id;
2984 struct non_default_uvs_table
2986   UInt32 num_uvs_mappings;
2987   struct uvs_mapping uvs_mappings[1];
2989 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
2990   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
2991 #pragma pack(pop)
2993 /* Read big endian values.  The argument LVAL must be an lvalue.  */
2994 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
2995    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
2996    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
2997 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
2998 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
2999 /* Succeeding one byte should also be accessible.  */
3000 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3001 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3003 /* Return UVS subtable for the specified FONT.  If the subtable is not
3004    found or ill-formatted, then return NULL.  */
3006 static CFDataRef
3007 mac_font_copy_uvs_table (FontRef font)
3009   CFDataRef cmap_table, uvs_table = NULL;
3011   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3012   if (cmap_table)
3013     {
3014       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3015       struct uvs_table *uvs;
3016       struct variation_selector_record *records;
3017       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3019 #if __LP64__
3020       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3021         goto finish;
3022 #endif
3024       cmap_len = CFDataGetLength (cmap_table);
3025       if (sizeof_sfntCMapHeader > cmap_len)
3026         goto finish;
3028       ntables = BUINT16_VALUE (cmap->numTables);
3029       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3030                      / sizeof_sfntCMapEncoding))
3031         goto finish;
3033       for (i = 0; i < ntables; i++)
3034         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3035              == kFontUnicodePlatform)
3036             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3037                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3038           {
3039             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3040             break;
3041           }
3042       if (i == ntables
3043           || uvs_offset > cmap_len
3044           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3045         goto finish;
3047       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3048       uvs_len = BUINT32_VALUE (uvs->length);
3049       if (uvs_len > cmap_len - uvs_offset
3050           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3051         goto finish;
3053       if (BUINT16_VALUE (uvs->format) != 14)
3054         goto finish;
3056       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3057       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3058                       / sizeof (struct variation_selector_record)))
3059         goto finish;
3061       records = uvs->variation_selector_records;
3062       for (i = 0; i < nrecords; i++)
3063         {
3064           UInt32 default_uvs_offset, non_default_uvs_offset;
3066           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3067           if (default_uvs_offset)
3068             {
3069               struct default_uvs_table *default_uvs;
3070               UInt32 nranges;
3072               if (default_uvs_offset > uvs_len
3073                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3074                       > uvs_len - default_uvs_offset))
3075                 goto finish;
3077               default_uvs = ((struct default_uvs_table *)
3078                              ((UInt8 *) uvs + default_uvs_offset));
3079               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3080               if (nranges > ((uvs_len - default_uvs_offset
3081                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3082                              / sizeof (struct unicode_value_range)))
3083                 goto finish;
3084               /* Now 2 * nranges can't overflow, so we can safely use
3085                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3086                  mac_font_get_glyphs_for_variants.  */
3087             }
3089           non_default_uvs_offset =
3090             BUINT32_VALUE (records[i].non_default_uvs_offset);
3091           if (non_default_uvs_offset)
3092             {
3093               struct non_default_uvs_table *non_default_uvs;
3094               UInt32 nmappings;
3096               if (non_default_uvs_offset > uvs_len
3097                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3098                       > uvs_len - non_default_uvs_offset))
3099                 goto finish;
3101               non_default_uvs = ((struct non_default_uvs_table *)
3102                                  ((UInt8 *) uvs + non_default_uvs_offset));
3103               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3104               if (nmappings > ((uvs_len - non_default_uvs_offset
3105                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3106                                / sizeof (struct uvs_mapping)))
3107                 goto finish;
3108               /* Now 2 * nmappings can't overflow, so we can safely
3109                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3110                  in mac_font_get_glyphs_for_variants.  */
3111             }
3112         }
3114       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3116     finish:
3117       CFRelease (cmap_table);
3118     }
3120   return uvs_table;
3123 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3124    sequence consisting of the given base character C and each
3125    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3126    result (explained below) into the corresponding GLYPHS[i].  If the
3127    entry is found in the Default UVS Table, then the result is 0.  If
3128    the entry is found in the Non-Default UVS Table, then the result is
3129    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3130    elements in SELECTORS must be sorted in strictly increasing
3131    order.  */
3133 static void
3134 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3135                                   const UTF32Char selectors[], CGGlyph glyphs[],
3136                                   CFIndex count)
3138   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3139   struct variation_selector_record *records = uvs->variation_selector_records;
3140   CFIndex i;
3141   UInt32 ir, nrecords;
3142 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3143   dispatch_queue_t queue =
3144     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3145   dispatch_group_t group = dispatch_group_create ();
3146 #endif
3148   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3149   i = 0;
3150   ir = 0;
3151   while (i < count && ir < nrecords)
3152     {
3153       UInt32 default_uvs_offset, non_default_uvs_offset;
3155       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3156         {
3157           glyphs[i++] = kCGFontIndexInvalid;
3158           continue;
3159         }
3160       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3161         {
3162           ir++;
3163           continue;
3164         }
3166       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3167       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3168       non_default_uvs_offset =
3169         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3170 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3171       dispatch_group_async (group, queue, ^{
3172 #endif
3173           glyphs[i] = kCGFontIndexInvalid;
3175           if (default_uvs_offset)
3176             {
3177               struct default_uvs_table *default_uvs =
3178                 (struct default_uvs_table *) ((UInt8 *) uvs
3179                                               + default_uvs_offset);
3180               struct unicode_value_range *ranges =
3181                 default_uvs->unicode_value_ranges;
3182               UInt32 lo, hi;
3184               lo = 0;
3185               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3186               while (lo < hi)
3187                 {
3188                   UInt32 mid = (lo + hi) / 2;
3190                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3191                     hi = mid;
3192                   else
3193                     lo = mid + 1;
3194                 }
3195               if (hi > 0
3196                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3197                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3198                 glyphs[i] = 0;
3199             }
3201           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3202             {
3203               struct non_default_uvs_table *non_default_uvs =
3204                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3205                                                   + non_default_uvs_offset);
3206               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3207               UInt32 lo, hi;
3209               lo = 0;
3210               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3211               while (lo < hi)
3212                 {
3213                   UInt32 mid = (lo + hi) / 2;
3215                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3216                     hi = mid;
3217                   else
3218                     lo = mid + 1;
3219                 }
3220               if (hi > 0 &&
3221                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3222                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3223             }
3224 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3225         });
3226 #endif
3227       i++;
3228       ir++;
3229     }
3230   while (i < count)
3231     glyphs[i++] = kCGFontIndexInvalid;
3232 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3233   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3234   dispatch_release (group);
3235 #endif
3238 static int
3239 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3241   CFDataRef uvs_table;
3242   CharacterCollection uvs_collection;
3243   int i, n = 0;
3245   block_input ();
3246   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3248   if (uvs_table)
3249     {
3250       UTF32Char selectors[256];
3251       CGGlyph glyphs[256];
3253       for (i = 0; i < 16; i++)
3254         selectors[i] = 0xFE00 + i;
3255       for (; i < 256; i++)
3256         selectors[i] = 0xE0100 + (i - 16);
3257       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3258       for (i = 0; i < 256; i++)
3259         {
3260           CGGlyph glyph = glyphs[i];
3262           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3263               && glyph != kCGFontIndexInvalid)
3264             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3265           if (glyph == kCGFontIndexInvalid)
3266             variations[i] = 0;
3267           else
3268             {
3269               variations[i] = (glyph ? glyph
3270                                : macfont_get_glyph_for_character (font, c));
3271               n++;
3272             }
3273         }
3274     }
3275   unblock_input ();
3277   return n;
3280 static const char *const macfont_booleans[] = {
3281   ":antialias",
3282   ":minspace",
3283   NULL,
3286 static const char *const macfont_non_booleans[] = {
3287   ":lang",
3288   ":script",
3289   ":destination",
3290   NULL,
3293 static void
3294 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3296   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3299 static Boolean
3300 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3301                                           CFArrayRef languages)
3303   Boolean result = true;
3304   CFArrayRef desc_languages =
3305     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3307   if (desc_languages == NULL)
3308     result = false;
3309   else
3310     {
3311       CFIndex desc_languages_count, i, languages_count;
3313       desc_languages_count = CFArrayGetCount (desc_languages);
3314       languages_count = CFArrayGetCount (languages);
3315       for (i = 0; i < languages_count; i++)
3316         if (!CFArrayContainsValue (desc_languages,
3317                                    CFRangeMake (0, desc_languages_count),
3318                                    CFArrayGetValueAtIndex (languages, i)))
3319           {
3320             result = false;
3321             break;
3322           }
3323       CFRelease (desc_languages);
3324     }
3326   return result;
3329 static CFStringRef
3330 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3332   CFStringRef result = NULL;
3333   CFStringRef charset_string =
3334     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3336   if (charset_string && CFStringGetLength (charset_string) > 0)
3337     {
3338       CFAttributedStringRef attr_string = NULL;
3339       CTLineRef ctline = NULL;
3340       CFDictionaryRef attrs =
3341         CFDictionaryCreate (NULL, NULL, NULL, 0,
3342                             &kCFTypeDictionaryKeyCallBacks,
3343                             &kCFTypeDictionaryValueCallBacks);
3345       if (attrs)
3346         {
3347           attr_string = CFAttributedStringCreate (NULL, charset_string, attrs);
3348           CFRelease (attrs);
3349         }
3350       if (attr_string)
3351         {
3352           ctline = CTLineCreateWithAttributedString (attr_string);
3353           CFRelease (attr_string);
3354         }
3355       if (ctline)
3356         {
3357           CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3358           CFIndex i, nruns = CFArrayGetCount (runs);
3359           CTFontRef font;
3361           for (i = 0; i < nruns; i++)
3362             {
3363               CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3364               CFDictionaryRef attributes = CTRunGetAttributes (run);
3365               CTFontRef font_in_run;
3367               if (attributes == NULL)
3368                 break;
3369               font_in_run =
3370                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3371               if (font_in_run == NULL)
3372                 break;
3373               if (i == 0)
3374                 font = font_in_run;
3375               else if (!mac_ctfont_equal_in_postscript_name (font, font_in_run))
3376                 break;
3377             }
3378           if (nruns > 0 && i == nruns)
3379             result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3380           CFRelease (ctline);
3381         }
3382     }
3384   return result;
3387 static inline double
3388 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3390   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3391                                      &glyph, NULL, 1);
3394 static inline CGRect
3395 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3397   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3398                                           &glyph, NULL, 1);
3401 static CFArrayRef
3402 mac_ctfont_create_available_families (void)
3404   CFMutableArrayRef families = NULL;
3406 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3407 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3408   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3409 #endif
3410     {
3411       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3413       if (orig_families)
3414         {
3415           CFIndex i, count = CFArrayGetCount (orig_families);
3417           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3418           if (families)
3419             for (i = 0; i < count; i++)
3420               {
3421                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3423                 if (!CFStringHasPrefix (family, CFSTR ("."))
3424                     && (CTFontManagerCompareFontFamilyNames (family,
3425                                                              CFSTR ("LastResort"),
3426                                                              NULL)
3427                         != kCFCompareEqualTo))
3428                   CFArrayAppendValue (families, family);
3429               }
3430           CFRelease (orig_families);
3431         }
3432     }
3433 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3434   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3435 #endif
3436 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3437 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3438     {
3439       CTFontCollectionRef collection;
3440       CFArrayRef descs = NULL;
3442       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3443       if (collection)
3444         {
3445           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3446           CFRelease (collection);
3447         }
3448       if (descs)
3449         {
3450           CFIndex i, count = CFArrayGetCount (descs);
3452           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3453           if (families)
3454             for (i = 0; i < count; i++)
3455               {
3456                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3457                 CFStringRef name =
3458                   mac_font_descriptor_copy_attribute (desc,
3459                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3461                 if (name)
3462                   {
3463                     CFIndex p, limit = CFArrayGetCount (families);
3465                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3466                                               (const void *) name,
3467                                               mac_font_family_compare, NULL);
3468                     if (p >= limit)
3469                       CFArrayAppendValue (families, name);
3470                     else if (mac_font_family_compare
3471                              (CFArrayGetValueAtIndex (families, p),
3472                               name, NULL) != kCFCompareEqualTo)
3473                       CFArrayInsertValueAtIndex (families, p, name);
3474                     CFRelease (name);
3475                   }
3476               }
3477           CFRelease (descs);
3478         }
3479     }
3480 #endif
3482   return families;
3485 static Boolean
3486 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3488   Boolean result;
3489   CFStringRef name1, name2;
3491   if (font1 == font2)
3492     return true;
3494   result = false;
3495   name1 = CTFontCopyPostScriptName (font1);
3496   if (name1)
3497     {
3498       name2 = CTFontCopyPostScriptName (font2);
3499       if (name2)
3500         {
3501           result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3502           CFRelease (name2);
3503         }
3504       CFRelease (name1);
3505     }
3507   return result;
3510 static CTLineRef
3511 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3512                                              CTFontRef macfont)
3514   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3515   CFTypeRef values[] = {NULL, NULL};
3516   CFDictionaryRef attributes = NULL;
3517   CFAttributedStringRef attr_string = NULL;
3518   CTLineRef ctline = NULL;
3519   float float_zero = 0.0f;
3521   values[0] = macfont;
3522   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3523   if (values[1])
3524     {
3525       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3526                                        (const void **) values,
3527                                        sizeof (keys) / sizeof (keys[0]),
3528                                        &kCFTypeDictionaryKeyCallBacks,
3529                                        &kCFTypeDictionaryValueCallBacks);
3530       CFRelease (values[1]);
3531     }
3532   if (attributes)
3533     {
3534       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3535       CFRelease (attributes);
3536     }
3537   if (attr_string)
3538     {
3539       ctline = CTLineCreateWithAttributedString (attr_string);
3540       CFRelease (attr_string);
3541     }
3542   if (ctline)
3543     {
3544       /* Abandon if ctline contains some fonts other than the
3545          specified one.  */
3546       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3547       CFIndex i, nruns = CFArrayGetCount (runs);
3549       for (i = 0; i < nruns; i++)
3550         {
3551           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3552           CFDictionaryRef attributes = CTRunGetAttributes (run);
3553           CTFontRef font_in_run;
3555           if (attributes == NULL)
3556             break;
3557           font_in_run =
3558             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3559           if (font_in_run == NULL)
3560             break;
3561           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3562             break;
3563         }
3564       if (i < nruns)
3565         {
3566           CFRelease (ctline);
3567           ctline = NULL;
3568         }
3569     }
3571   return ctline;
3574 CFIndex
3575 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3576                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3578   CFIndex used, result = 0;
3579   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3581   if (ctline == NULL)
3582     return 0;
3584   used = CTLineGetGlyphCount (ctline);
3585   if (used <= glyph_len)
3586     {
3587       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3588       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3589       CGFloat total_advance = 0;
3590       CFIndex total_glyph_count = 0;
3592       for (k = 0; k < ctrun_count; k++)
3593         {
3594           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3595           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3596           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3597           CFRange string_range, comp_range, range;
3598           CFIndex *permutation;
3600           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3601             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3602           else
3603             permutation = NULL;
3605 #define RIGHT_TO_LEFT_P permutation
3607           /* Now the `comp_range' member of struct mac_glyph_layout is
3608              temporarily used as a work area such that:
3609               glbuf[i].comp_range.location =
3610                 min {compRange[i + 1].location, ...,
3611                      compRange[glyph_count - 1].location,
3612                      maxRange (stringRangeForCTRun)}
3613               glbuf[i].comp_range.length = maxRange (compRange[i])
3614              where compRange[i] is the range of composed characters
3615              containing i-th glyph.  */
3616           string_range = CTRunGetStringRange (ctrun);
3617           min_location = string_range.location + string_range.length;
3618           for (i = 0; i < glyph_count; i++)
3619             {
3620               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3621               CFIndex glyph_index;
3622               CFRange rng;
3624               if (!RIGHT_TO_LEFT_P)
3625                 glyph_index = glyph_count - i - 1;
3626               else
3627                 glyph_index = i;
3628               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3629                                      &gl->string_index);
3630               rng =
3631                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3632                                                              gl->string_index);
3633               gl->comp_range.location = min_location;
3634               gl->comp_range.length = rng.location + rng.length;
3635               if (rng.location < min_location)
3636                 min_location = rng.location;
3637             }
3639           /* Fill the `comp_range' member of struct mac_glyph_layout,
3640              and setup a permutation for right-to-left text.  */
3641           comp_range = CFRangeMake (string_range.location, 0);
3642           range = CFRangeMake (0, 0);
3643           while (1)
3644             {
3645               struct mac_glyph_layout *gl =
3646                 glbuf + range.location + range.length;
3648               if (gl->comp_range.length
3649                   > comp_range.location + comp_range.length)
3650                 comp_range.length = gl->comp_range.length - comp_range.location;
3651               min_location = gl->comp_range.location;
3652               range.length++;
3654               if (min_location >= comp_range.location + comp_range.length)
3655                 {
3656                   comp_range.length = min_location - comp_range.location;
3657                   for (i = 0; i < range.length; i++)
3658                     {
3659                       glbuf[range.location + i].comp_range = comp_range;
3660                       if (RIGHT_TO_LEFT_P)
3661                         permutation[range.location + i] =
3662                           range.location + range.length - i - 1;
3663                     }
3665                   comp_range = CFRangeMake (min_location, 0);
3666                   range.location += range.length;
3667                   range.length = 0;
3668                   if (range.location == glyph_count)
3669                     break;
3670                 }
3671             }
3673           /* Then fill the remaining members.  */
3674           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3675                range.location++)
3676             {
3677               struct mac_glyph_layout *gl;
3678               CGPoint position;
3680               if (!RIGHT_TO_LEFT_P)
3681                 gl = glbuf + range.location;
3682               else
3683                 {
3684                   CFIndex src, dest;
3686                   src = glyph_count - 1 - range.location;
3687                   dest = permutation[src];
3688                   gl = glbuf + dest;
3689                   if (src < dest)
3690                     {
3691                       CFIndex tmp = gl->string_index;
3693                       gl->string_index = glbuf[src].string_index;
3694                       glbuf[src].string_index = tmp;
3695                     }
3696                 }
3697               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3699               CTRunGetPositions (ctrun, range, &position);
3700               gl->advance_delta = position.x - total_advance;
3701               gl->baseline_delta = position.y;
3702               gl->advance = (gl->advance_delta
3703                              + CTRunGetTypographicBounds (ctrun, range,
3704                                                           NULL, NULL, NULL));
3705               total_advance += gl->advance;
3706             }
3708           if (RIGHT_TO_LEFT_P)
3709             xfree (permutation);
3711 #undef RIGHT_TO_LEFT_P
3713           total_glyph_count += glyph_count;
3714         }
3716       result = used;
3717     }
3718   CFRelease (ctline);
3720   return result;
3723 /* The function below seems to cause a memory leak for the CFString
3724    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3725    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3726 #if USE_CT_GLYPH_INFO
3727 CGGlyph
3728 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3729                               CGFontIndex cid)
3731   CGGlyph result = kCGFontIndexInvalid;
3732   UniChar characters[] = {0xfffd};
3733   CFStringRef string;
3734   CFAttributedStringRef attr_string = NULL;
3735   CTLineRef ctline = NULL;
3737   string = CFStringCreateWithCharacters (NULL, characters,
3738                                          sizeof (characters)
3739                                          / sizeof (characters[0]));
3740   if (string)
3741     {
3742       CTGlyphInfoRef glyph_info =
3743         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3744       CFDictionaryRef attributes = NULL;
3746       if (glyph_info)
3747         {
3748           CFStringRef keys[] = {kCTFontAttributeName,
3749                                 kCTGlyphInfoAttributeName};
3750           CFTypeRef values[] = {font, glyph_info};
3752           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3753                                            (const void **) values,
3754                                            sizeof (keys) / sizeof (keys[0]),
3755                                            &kCFTypeDictionaryKeyCallBacks,
3756                                            &kCFTypeDictionaryValueCallBacks);
3757           CFRelease (glyph_info);
3758         }
3759       if (attributes)
3760         {
3761           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3762           CFRelease (attributes);
3763         }
3764       CFRelease (string);
3765     }
3766   if (attr_string)
3767     {
3768       ctline = CTLineCreateWithAttributedString (attr_string);
3769       CFRelease (attr_string);
3770     }
3771   if (ctline)
3772     {
3773       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3775       if (CFArrayGetCount (runs) > 0)
3776         {
3777           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3778           CFDictionaryRef attributes = CTRunGetAttributes (run);
3780           if (attributes)
3781             {
3782               CTFontRef font_in_run =
3783                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3785               if (font_in_run
3786                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3787                 {
3788                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3789                   if (result >= CTFontGetGlyphCount (font))
3790                     result = kCGFontIndexInvalid;
3791                 }
3792             }
3793         }
3794       CFRelease (ctline);
3795     }
3797   return result;
3799 #endif
3801 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3802 static inline int
3803 mac_font_family_group (CFStringRef family)
3805   if (CFStringHasPrefix (family, CFSTR ("#")))
3806     return 2;
3807   else
3808     {
3809       CFRange range;
3811       range = CFStringFind (family, CFSTR ("Apple"),
3812                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3813       if (range.location != kCFNotFound)
3814         return 1;
3816       return 0;
3817     }
3820 CFComparisonResult
3821 mac_font_family_compare (const void *val1, const void *val2, void *context)
3823   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3824   int group1, group2;
3826   group1 = mac_font_family_group (family1);
3827   group2 = mac_font_family_group (family2);
3828   if (group1 < group2)
3829     return kCFCompareLessThan;
3830   if (group1 > group2)
3831     return kCFCompareGreaterThan;
3832   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3834 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3836 void *
3837 macfont_get_nsctfont (struct font *font)
3839   struct macfont_info *macfont_info = (struct macfont_info *) font;
3840   FontRef macfont = macfont_info->macfont;
3842   return (void *) macfont;
3845 void
3846 mac_register_font_driver (struct frame *f)
3848   register_font_driver (&macfont_driver, f);
3851 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3854 void
3855 syms_of_macfont (void)
3857 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3858   static struct font_driver mac_font_driver;
3860   DEFSYM (Qmac_ct, "mac-ct");
3861   macfont_driver.type = Qmac_ct;
3862   register_font_driver (&macfont_driver, NULL);
3864   DEFSYM (QCdestination, ":destination");
3865   DEFSYM (QCminspace, ":minspace");
3866 #endif