* bytecode.c (exec_byte_code): Use some more volatile variables
[emacs.git] / src / macfont.m
blob206a810c239d15d742ef87f6459b017a8e7fa160
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 WYSIWIG, 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];
369       
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   CGContextSetFillColorWithColor (context,                              \
628                                   get_cgcolor (NS_FACE_FOREGROUND (s->face), \
629                                                s->f))
631 #define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, s)                \
632   CGContextSetFillColorWithColor (context,                              \
633                                   get_cgcolor (NS_FACE_BACKGROUND (s->face), \
634                                                s->f))
636 #define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, s)              \
637   CGContextSetStrokeColorWithColor (context,                            \
638                                     get_cgcolor (NS_FACE_FOREGROUND (s->face),\
639                                                  s->f))
642 /* Mac font driver.  */
644 static struct
646   /* registry name */
647   const char *name;
648   /* characters to distinguish the charset from the others */
649   int uniquifier[6];
650   /* additional constraint by language */
651   CFStringRef lang;
652   /* set on demand */
653   CFCharacterSetRef cf_charset;
654   CFStringRef cf_charset_string;
655 } cf_charset_table[] =
656   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
657     { "iso8859-2", { 0x00A0, 0x010E }},
658     { "iso8859-3", { 0x00A0, 0x0108 }},
659     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
660     { "iso8859-5", { 0x00A0, 0x0401 }},
661     { "iso8859-6", { 0x00A0, 0x060C }},
662     { "iso8859-7", { 0x00A0, 0x0384 }},
663     { "iso8859-8", { 0x00A0, 0x05D0 }},
664     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
665     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
666     { "iso8859-11", { 0x00A0, 0x0E01 }},
667     { "iso8859-13", { 0x00A0, 0x201C }},
668     { "iso8859-14", { 0x00A0, 0x0174 }},
669     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
670     { "iso8859-16", { 0x00A0, 0x0218}},
671     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
672     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0xF7E5 }, CFSTR ("zh-Hant") },
673     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
674     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
675     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
676     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
677     { "cns11643.1992-3", { 0x201A9 }},
678     { "cns11643.1992-4", { 0x20057 }},
679     { "cns11643.1992-5", { 0x20000 }},
680     { "cns11643.1992-6", { 0x20003 }},
681     { "cns11643.1992-7", { 0x20055 }},
682     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
683     { "jisx0212.1990-0", { 0x4E44 }},
684     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
685     { "jisx0213.2000-2", { 0xFA49 }},
686     { "jisx0213.2004-1", { 0x20B9F }},
687     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
688     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
689     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
690     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
691     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
692     { "unicode-sip", { 0x20000 }},
693     { NULL }
694   };
696 static CGFloat macfont_antialias_threshold;
698 void
699 macfont_update_antialias_threshold (void)
701   int threshold;
702   Boolean valid_p;
704   threshold =
705     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
706                                      kCFPreferencesCurrentApplication,
707                                      &valid_p);
708   if (valid_p)
709     macfont_antialias_threshold = threshold;
712 static inline Lisp_Object
713 macfont_intern_prop_cfstring (CFStringRef cfstring)
715   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
717   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
720 static inline CFIndex
721 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
723   if (c < 0x10000)
724     {
725       unichars[0] = c;
727       return 1;
728     }
729   else
730     {
731       c -= 0x10000;
732       unichars[0] = (c >> 10) + 0xD800;
733       unichars[1] = (c & 0x3FF) + 0xDC00;
735       return 2;
736     }
739 static Boolean
740 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
741                                          FontSymbolicTraits *sym_traits)
743   SInt64 sint64_value;
745   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
746      OS 10.6 when the value is greater than or equal to 1 << 31.  */
747   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
748     {
749       *sym_traits = (FontSymbolicTraits) sint64_value;
751       return true;
752     }
754   return false;
757 static void
758 macfont_store_descriptor_attributes (FontDescriptorRef desc,
759                                      Lisp_Object spec_or_entity)
761   CFStringRef str;
762   CFDictionaryRef dict;
763   CFNumberRef num;
764   CGFloat floatval;
766   str = mac_font_descriptor_copy_attribute (desc,
767                                             MAC_FONT_FAMILY_NAME_ATTRIBUTE);
768   if (str)
769     {
770       ASET (spec_or_entity, FONT_FAMILY_INDEX,
771             macfont_intern_prop_cfstring (str));
772       CFRelease (str);
773     }
774   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
775   if (dict)
776     {
777       struct {
778         enum font_property_index index;
779         CFStringRef trait;
780         CGPoint points[6];
781       } numeric_traits[] =
782           {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
783             {{-0.4, 50},        /* light */
784              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
785              {0, 100},          /* normal */
786              {0.24, 140},       /* (semi-bold + normal) / 2 */
787              {0.4, 200},        /* bold */
788              {CGFLOAT_MAX, CGFLOAT_MAX}}},
789            {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
790             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
791            {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
792             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
793       int i;
795       for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); i++)
796         {
797           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
798           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
799             {
800               CGPoint *point = numeric_traits[i].points;
802               while (point->x < floatval)
803                 point++;
804               if (point == numeric_traits[i].points)
805                 point++;
806               else if (point->x == CGFLOAT_MAX)
807                 point--;
808               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
809                                            * ((point->y - (point - 1)->y)
810                                               / (point->x - (point - 1)->x)));
811               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
812                               make_number (lround (floatval)));
813             }
814         }
816       num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
817       if (num)
818         {
819           FontSymbolicTraits sym_traits;
820           int spacing;
822           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
823           spacing = (sym_traits & MAC_FONT_TRAIT_MONO_SPACE
824                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
825           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
826         }
828       CFRelease (dict);
829     }
830   num = mac_font_descriptor_copy_attribute (desc, MAC_FONT_SIZE_ATTRIBUTE);
831   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
832     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
833   else
834     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
835   if (num)
836     CFRelease (num);
839 static Lisp_Object
840 macfont_descriptor_entity (FontDescriptorRef desc, Lisp_Object extra,
841                            FontSymbolicTraits synth_sym_traits)
843   Lisp_Object entity;
844   CFDictionaryRef dict;
845   FontSymbolicTraits sym_traits = 0;
846   CFStringRef name;
848   entity = font_make_entity ();
850   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
851   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
853   macfont_store_descriptor_attributes (desc, entity);
855   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
856   if (dict)
857     {
858       CFNumberRef num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
860       if (num)
861         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
862       CFRelease (dict);
863     }
864   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
865     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
866   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
867   name = mac_font_descriptor_copy_attribute (desc, MAC_FONT_NAME_ATTRIBUTE);
868   font_put_extra (entity, QCfont_entity,
869                   make_save_ptr_int ((void *) name, sym_traits));
870   if (synth_sym_traits & MAC_FONT_TRAIT_ITALIC)
871     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
872                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
873   if (synth_sym_traits & MAC_FONT_TRAIT_BOLD)
874     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
875                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
876   if (synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
877     ASET (entity, FONT_SPACING_INDEX,
878           make_number (FONT_SPACING_SYNTHETIC_MONO));
880   return entity;
883 static CFStringRef
884 macfont_create_family_with_symbol (Lisp_Object symbol)
886   static CFArrayRef families = NULL;
887   CFStringRef result = NULL, family_name;
888   int using_cache_p = 1;
889   CFComparatorFunction family_name_comparator;
891   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
892   if (family_name == NULL)
893     return NULL;
895 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
896 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
897   if (CTFontManagerCompareFontFamilyNames != NULL)
898 #endif
899     {
900       family_name_comparator = CTFontManagerCompareFontFamilyNames;
901     }
902 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
903   else               /* CTFontManagerCompareFontFamilyNames == NULL */
904 #endif
905 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
906 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
907     {
908       family_name_comparator = mac_font_family_compare;
909     }
910 #endif
912   if ((*family_name_comparator) (family_name, CFSTR ("LastResort"), NULL)
913       == kCFCompareEqualTo)
914     result = CFSTR ("LastResort");
915   else
916     while (1)
917       {
918         CFIndex i, count;
920         if (families == NULL)
921           {
922             families = mac_font_create_available_families ();
923             using_cache_p = 0;
924             if (families == NULL)
925               break;
926           }
928         count = CFArrayGetCount (families);
929         i = CFArrayBSearchValues (families, CFRangeMake (0, count),
930                                   (const void *) family_name,
931                                   family_name_comparator, NULL);
932         if (i < count)
933           {
934             CFStringRef name = CFArrayGetValueAtIndex (families, i);
936             if ((*family_name_comparator) (name, family_name, NULL)
937                 == kCFCompareEqualTo)
938               result = CFRetain (name);
939           }
941         if (result || !using_cache_p)
942           break;
943         else
944           {
945             CFRelease (families);
946             families = NULL;
947           }
948       }
950   CFRelease (family_name);
952   return result;
955 #define WIDTH_FRAC_BITS         (4)
956 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
958 struct macfont_metrics
960   unsigned char lbearing_low, rbearing_low;
961   signed lbearing_high : 4, rbearing_high : 4;
962   unsigned char ascent_low, descent_low;
963   signed ascent_high : 4, descent_high : 4;
965   /* These two members are used for fixed-point representation of
966      glyph width.  The `width_int' member is an integer that is
967      closest to the width.  The `width_frac' member is the fractional
968      adjustment representing a value in [-.5, .5], multiplied by
969      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
970      the advance delta for centering instead of the glyph width.  */
971   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
974 #define METRICS_VALUE(metrics, member) \
975   (((metrics)->member##_high << 8) | (metrics)->member##_low)
976 #define METRICS_SET_VALUE(metrics, member, value) \
977   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff; \
978       (metrics)->member##_high = tmp >> 8;} while (0)
980 enum metrics_status
981   {
982     METRICS_INVALID = -1,    /* metrics entry is invalid */
983     METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
984   };
986 #define METRICS_STATUS(metrics) \
987   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
988 #define METRICS_SET_STATUS(metrics, status) \
989   do {METRICS_SET_VALUE (metrics, ascent, 0); \
990       METRICS_SET_VALUE (metrics, descent, status);} while (0)
992 #define METRICS_NCOLS_PER_ROW   (128)
993 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
994 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
996 static int
997 macfont_glyph_extents (struct font *font, CGGlyph glyph,
998                        struct font_metrics *metrics, CGFloat *advance_delta,
999                        int force_integral_p)
1001   struct macfont_info *macfont_info = (struct macfont_info *) font;
1002   FontRef macfont = macfont_info->macfont;
1003   int row, col;
1004   struct macfont_metrics *cache;
1005   int width;
1007   row = glyph / METRICS_NCOLS_PER_ROW;
1008   col = glyph % METRICS_NCOLS_PER_ROW;
1009   if (row >= macfont_info->metrics_nrows)
1010     {
1011       macfont_info->metrics =
1012         xrealloc (macfont_info->metrics,
1013                   sizeof (struct macfont_metrics *) * (row + 1));
1014       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1015               (sizeof (struct macfont_metrics *)
1016                * (row + 1 - macfont_info->metrics_nrows)));
1017       macfont_info->metrics_nrows = row + 1;
1018     }
1019   if (macfont_info->metrics[row] == NULL)
1020     {
1021       struct macfont_metrics *new;
1022       int i;
1024       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1025       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1026         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1027       macfont_info->metrics[row] = new;
1028     }
1029   cache = macfont_info->metrics[row] + col;
1031   if (METRICS_STATUS (cache) == METRICS_INVALID)
1032     {
1033       CGFloat fwidth;
1035       if (macfont_info->screen_font)
1036         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1037       else
1038         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1040       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1041          advance delta value.  */
1042       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1043         fwidth = (font->pixel_size - fwidth) / 2;
1044       cache->width_int = lround (fwidth);
1045       cache->width_frac = lround ((fwidth - cache->width_int)
1046                                   * WIDTH_FRAC_SCALE);
1047       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1048     }
1049   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1050     width = font->pixel_size;
1051   else
1052     width = cache->width_int;
1054   if (metrics)
1055     {
1056       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1057         {
1058           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1060           if (macfont_info->synthetic_italic_p)
1061             {
1062               /* We assume the members a, b, c, and d in
1063                  synthetic_italic_atfm are non-negative.  */
1064               bounds.origin =
1065                 CGPointApplyAffineTransform (bounds.origin,
1066                                              synthetic_italic_atfm);
1067               bounds.size =
1068                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1069             }
1070           if (macfont_info->synthetic_bold_p)
1071             {
1072               CGFloat d =
1073                 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1075               bounds = CGRectInset (bounds, d, d);
1076             }
1077           switch (macfont_info->spacing)
1078             {
1079             case MACFONT_SPACING_PROPORTIONAL:
1080               bounds.origin.x += - (cache->width_frac
1081                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1082               break;
1083             case MACFONT_SPACING_MONO:
1084               break;
1085             case MACFONT_SPACING_SYNTHETIC_MONO:
1086               bounds.origin.x += (cache->width_int
1087                                   + (cache->width_frac
1088                                      / (CGFloat) WIDTH_FRAC_SCALE));
1089               break;
1090             }
1091           if (bounds.size.width > 0)
1092             {
1093               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1094               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1095                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1096             }
1097           bounds = CGRectIntegral (bounds);
1098           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1099           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1100           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1101           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1102         }
1103       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1104       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1105       metrics->width = width;
1106       metrics->ascent = METRICS_VALUE (cache, ascent);
1107       metrics->descent = METRICS_VALUE (cache, descent);
1108     }
1110   if (advance_delta)
1111     {
1112       switch (macfont_info->spacing)
1113         {
1114         case MACFONT_SPACING_PROPORTIONAL:
1115           *advance_delta = (force_integral_p ? 0
1116                             : - (cache->width_frac
1117                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1118           break;
1119         case MACFONT_SPACING_MONO:
1120           *advance_delta = 0;
1121           break;
1122         case MACFONT_SPACING_SYNTHETIC_MONO:
1123           *advance_delta = (force_integral_p ? cache->width_int
1124                             : (cache->width_int
1125                                + (cache->width_frac
1126                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1127           break;
1128         }
1129     }
1131   return width;
1134 static CFMutableDictionaryRef macfont_cache_dictionary;
1136 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1137    equal to the number of rows that are invalid as BMP (i.e., from
1138    U+D800 to U+DFFF).  */
1139 #define ROW_PERM_OFFSET (8)
1141 /* The number of glyphs that can be stored in a value for a single
1142    entry of CFDictionary.  */
1143 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1145 struct macfont_cache
1147   int reference_count;
1148   CFCharacterSetRef cf_charset;
1149   struct {
1150     /* The cached glyph for a BMP character c is stored in
1151        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1152        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1153     unsigned char row_nkeys_or_perm[256];
1154     CGGlyph **matrix;
1156     /* Number of rows for which the BMP cache is allocated so far.
1157        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1158     int nrows;
1160     /* The cached glyph for a character c is stored as the (c %
1161        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1162        NGLYPHS_IN_VALUE).  However, the glyph for a BMP characrer c is
1163        not stored here if row_nkeys_or_perm[c / 256] >=
1164        ROW_PERM_OFFSET.  */
1165     CFMutableDictionaryRef dictionary;
1166   } glyph;
1168   struct {
1169     /* UVS (Unicode Variation Sequence) subtable data, which is of
1170        type CFDataRef if available.  NULL means it is not initialized
1171        yet.  kCFNull means the subtable is not found and there is no
1172        suitable fallback table for this font.  */
1173     CFTypeRef table;
1175     /* Character collection specifying the destination of the mapping
1176        provided by `table' above.  If `table' is obtained from the UVS
1177        subtable in the font cmap table, then the value of this member
1178        should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING.  */
1179     CharacterCollection collection;
1180   } uvs;
1183 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1184 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1185 static void macfont_release_cache (struct macfont_cache *);
1186 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1187 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1188 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1189 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1190                                           CharacterCollection, CGFontIndex);
1191 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1193 static struct macfont_cache *
1194 macfont_lookup_cache (CFStringRef key)
1196   struct macfont_cache *cache;
1198   if (macfont_cache_dictionary == NULL)
1199     {
1200       macfont_cache_dictionary =
1201         CFDictionaryCreateMutable (NULL, 0,
1202                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1203       cache = NULL;
1204     }
1205   else
1206     cache = ((struct macfont_cache *)
1207              CFDictionaryGetValue (macfont_cache_dictionary, key));
1209   if (cache == NULL)
1210     {
1211       FontRef macfont = mac_font_create_with_name (key, 0);
1213       if (macfont)
1214         {
1215           cache = xzalloc (sizeof (struct macfont_cache));
1216           /* Treat the LastResort font as if it contained glyphs for
1217              all characters.  This may look too rough, but neither
1218              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1219              for this font is correct for non-BMP characters on Mac OS
1220              X 10.5, anyway.  */
1221           if (CFStringCompare (key, CFSTR ("LastResort"), 0)
1222               == kCFCompareEqualTo)
1223             {
1224               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1226               cache->cf_charset =
1227                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1228             }
1229           if (cache->cf_charset == NULL)
1230             cache->cf_charset = mac_font_copy_character_set (macfont);
1231           CFDictionaryAddValue (macfont_cache_dictionary, key,
1232                                 (const void *) cache);
1233           CFRelease (macfont);
1234         }
1235     }
1237   return cache;
1240 static struct macfont_cache *
1241 macfont_retain_cache (struct macfont_cache *cache)
1243   cache->reference_count++;
1245   return cache;
1248 static void
1249 macfont_release_cache (struct macfont_cache *cache)
1251   if (--cache->reference_count == 0)
1252     {
1253       int i;
1255       for (i = 0; i < cache->glyph.nrows; i++)
1256         xfree (cache->glyph.matrix[i]);
1257       xfree (cache->glyph.matrix);
1258       if (cache->glyph.dictionary)
1259         CFRelease (cache->glyph.dictionary);
1260       memset (&cache->glyph, 0, sizeof (cache->glyph));
1261       if (cache->uvs.table)
1262         CFRelease (cache->uvs.table);
1263       memset (&cache->uvs, 0, sizeof (cache->uvs));
1264     }
1267 static CFCharacterSetRef
1268 macfont_get_cf_charset (struct font *font)
1270   struct macfont_info *macfont_info = (struct macfont_info *) font;
1272   return macfont_info->cache->cf_charset;
1275 static CFCharacterSetRef
1276 macfont_get_cf_charset_for_name (CFStringRef name)
1278   struct macfont_cache *cache = macfont_lookup_cache (name);
1280   return cache->cf_charset;
1283 static CGGlyph
1284 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1286   struct macfont_info *macfont_info = (struct macfont_info *) font;
1287   FontRef macfont = macfont_info->macfont;
1288   struct macfont_cache *cache = macfont_info->cache;
1290   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1291     {
1292       int row = c / 256;
1293       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1295       if (nkeys_or_perm < ROW_PERM_OFFSET)
1296         {
1297           UniChar unichars[256], ch;
1298           CGGlyph *glyphs;
1299           int i, len;
1300           int nrows;
1301 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1302           dispatch_queue_t queue;
1303           dispatch_group_t group = NULL;
1304 #else
1305           int nkeys;
1306 #endif
1308           if (row != 0)
1309             {
1310               CFMutableDictionaryRef dictionary;
1311               uintptr_t key, value;
1312               int nshifts;
1313               CGGlyph glyph;
1315               if (cache->glyph.dictionary == NULL)
1316                 cache->glyph.dictionary =
1317                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1318               dictionary = cache->glyph.dictionary;
1319               key = c / NGLYPHS_IN_VALUE;
1320               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1321               value = ((uintptr_t)
1322                        CFDictionaryGetValue (dictionary, (const void *) key));
1323               glyph = (value >> nshifts);
1324               if (glyph)
1325                 return glyph;
1327               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1328                 {
1329                   ch = c;
1330                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1331                                                            &glyph, 1)
1332                       || glyph == 0)
1333                     glyph = kCGFontIndexInvalid;
1335                   if (value == 0)
1336                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1337                   value |= ((uintptr_t) glyph << nshifts);
1338                   CFDictionarySetValue (dictionary, (const void *) key,
1339                                         (const void *) value);
1341                   return glyph;
1342                 }
1344 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1345               queue =
1346                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1347               group = dispatch_group_create ();
1348               dispatch_group_async (group, queue, ^{
1349                   int nkeys;
1350                   uintptr_t key;
1351 #endif
1352                   nkeys = nkeys_or_perm;
1353                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1354                     if (CFDictionaryContainsKey (dictionary,
1355                                                  (const void *) key))
1356                       {
1357                         CFDictionaryRemoveValue (dictionary,
1358                                                  (const void *) key);
1359                         if (--nkeys == 0)
1360                           break;
1361                       }
1362 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1363                 });
1364 #endif
1365             }
1367           len = 0;
1368           for (i = 0; i < 256; i++)
1369             {
1370               ch = row * 256 + i;
1371               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1372                 unichars[len++] = ch;
1373             }
1375           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1376           if (len > 0)
1377             {
1378               mac_font_get_glyphs_for_characters (macfont, unichars,
1379                                                   glyphs, len);
1380               while (i > len)
1381                 {
1382                   int next = unichars[len - 1] % 256;
1384                   while (--i > next)
1385                     glyphs[i] = kCGFontIndexInvalid;
1387                   len--;
1388                   glyphs[i] = glyphs[len];
1389                   if (len == 0)
1390                     break;
1391                 }
1392             }
1393           if (i > len)
1394             while (i-- > 0)
1395               glyphs[i] = kCGFontIndexInvalid;
1397           nrows = cache->glyph.nrows;
1398           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1399           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1400           nrows++;
1401           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1402                                           sizeof (CGGlyph *) * nrows);
1403           cache->glyph.matrix[nrows - 1] = glyphs;
1404           cache->glyph.nrows = nrows;
1406 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1407           if (group)
1408             {
1409               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1410               dispatch_release (group);
1411             }
1412 #endif
1413         }
1415       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1416     }
1417   else
1418     {
1419       uintptr_t key, value;
1420       int nshifts;
1421       CGGlyph glyph;
1423       if (cache->glyph.dictionary == NULL)
1424         cache->glyph.dictionary =
1425           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1426       key = c / NGLYPHS_IN_VALUE;
1427       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1428       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1429                                                 (const void *) key);
1430       glyph = (value >> nshifts);
1431       if (glyph == 0)
1432         {
1433           UniChar unichars[2];
1434           CGGlyph glyphs[2];
1435           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1437           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1438                                                   count))
1439             glyph = glyphs[0];
1440           if (glyph == 0)
1441             glyph = kCGFontIndexInvalid;
1443           value |= ((uintptr_t) glyph << nshifts);
1444           CFDictionarySetValue (cache->glyph.dictionary,
1445                                 (const void *) key, (const void *) value);
1446         }
1448       return glyph;
1449     }
1452 static CGGlyph
1453 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1454                            CGFontIndex cid)
1456   struct macfont_info *macfont_info = (struct macfont_info *) font;
1457   FontRef macfont = macfont_info->macfont;
1459   /* Cache it? */
1460   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1463 static CFDataRef
1464 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1466   struct macfont_info *macfont_info = (struct macfont_info *) font;
1467   FontRef macfont = macfont_info->macfont;
1468   struct macfont_cache *cache = macfont_info->cache;
1469   CFDataRef result = NULL;
1471   if (cache->uvs.table == NULL)
1472     {
1473       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1474       CharacterCollection uvs_collection =
1475         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1477       if (uvs_table == NULL
1478           && mac_font_get_glyph_for_cid (macfont,
1479                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1480                                          6480) != kCGFontIndexInvalid)
1481         {
1482           /* If the glyph for U+4E55 is accessible via its CID 6480,
1483              then we use the Adobe-Japan1 UVS table, which maps a
1484              variation sequence to a CID, as a fallback.  */
1485           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1487           if (mac_uvs_table_adobe_japan1 == NULL)
1488             mac_uvs_table_adobe_japan1 =
1489               CFDataCreateWithBytesNoCopy (NULL,
1490                                            mac_uvs_table_adobe_japan1_bytes,
1491                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1492                                            kCFAllocatorNull);
1493           if (mac_uvs_table_adobe_japan1)
1494             {
1495               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1496               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1497             }
1498         }
1499       if (uvs_table == NULL)
1500         cache->uvs.table = kCFNull;
1501       else
1502         cache->uvs.table = uvs_table;
1503       cache->uvs.collection = uvs_collection;
1504     }
1506   if (cache->uvs.table != kCFNull)
1507     {
1508       result = cache->uvs.table;
1509       *collection = cache->uvs.collection;
1510     }
1512   return result;
1515 static Lisp_Object macfont_get_cache (struct frame *);
1516 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1517 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1518 static Lisp_Object macfont_list_family (struct frame *);
1519 static void macfont_free_entity (Lisp_Object);
1520 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1521 static void macfont_close (struct frame *, struct font *);
1522 static int macfont_has_char (Lisp_Object, int);
1523 static unsigned macfont_encode_char (struct font *, int);
1524 static int macfont_text_extents (struct font *, unsigned int *, int,
1525                                  struct font_metrics *);
1526 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1527 static Lisp_Object macfont_shape (Lisp_Object);
1528 static int macfont_variation_glyphs (struct font *, int c,
1529                                      unsigned variations[256]);
1530 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1532 static struct font_driver macfont_driver =
1533   {
1534     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1535     0,                          /* case insensitive */
1536     macfont_get_cache,
1537     macfont_list,
1538     macfont_match,
1539     macfont_list_family,
1540     macfont_free_entity,
1541     macfont_open,
1542     macfont_close,
1543     NULL,                       /* prepare_face */
1544     NULL,                       /* done_face */
1545     macfont_has_char,
1546     macfont_encode_char,
1547     macfont_text_extents,
1548     macfont_draw,
1549     NULL,                       /* get_bitmap */
1550     NULL,                       /* free_bitmap */
1551     NULL,                       /* get_outline */
1552     NULL,                       /* free_outline */
1553     NULL,                       /* anchor_point */
1554     NULL,                       /* otf_capability */
1555     NULL,                       /* otf_drive */
1556     NULL,                       /* start_for_frame */
1557     NULL,                       /* end_for_frame */
1558     macfont_shape,
1559     NULL,                       /* check */
1560     macfont_variation_glyphs,
1561     macfont_filter_properties,
1562   };
1564 static Lisp_Object
1565 macfont_get_cache (struct frame * f)
1567   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1569   return (dpyinfo->name_list_element);
1572 static int
1573 macfont_get_charset (Lisp_Object registry)
1575   char *str = SSDATA (SYMBOL_NAME (registry));
1576   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1577   Lisp_Object regexp;
1578   int i, j;
1580   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1581     {
1582       if (str[i] == '.')
1583         re[j++] = '\\';
1584       else if (str[i] == '*')
1585         re[j++] = '.';
1586       re[j] = str[i];
1587       if (re[j] == '?')
1588         re[j] = '.';
1589     }
1590   re[j] = '\0';
1591   regexp = make_unibyte_string (re, j);
1592   for (i = 0; cf_charset_table[i].name; i++)
1593     if (fast_c_string_match_ignore_case
1594         (regexp, cf_charset_table[i].name,
1595          strlen (cf_charset_table[i].name)) >= 0)
1596       break;
1597   if (! cf_charset_table[i].name)
1598     return -1;
1599   if (! cf_charset_table[i].cf_charset)
1600     {
1601       int *uniquifier = cf_charset_table[i].uniquifier;
1602       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1603       CFIndex count = 0;
1604       CFStringRef string;
1605       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1607       if (! charset)
1608         return -1;
1609       for (j = 0; uniquifier[j]; j++)
1610         {
1611           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1612                                                         unichars + count);
1613           CFCharacterSetAddCharactersInRange (charset,
1614                                               CFRangeMake (uniquifier[j], 1));
1615         }
1617       string = CFStringCreateWithCharacters (NULL, unichars, count);
1618       if (! string)
1619         {
1620           CFRelease (charset);
1621           return -1;
1622         }
1623       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1624                                                                  charset);
1625       CFRelease (charset);
1626       /* CFCharacterSetCreateWithCharactersInString does not handle
1627          surrogate pairs properly as of Mac OS X 10.5.  */
1628      cf_charset_table[i].cf_charset_string = string;
1629     }
1630   return i;
1633 struct OpenTypeSpec
1635   Lisp_Object script;
1636   unsigned int script_tag, langsys_tag;
1637   int nfeatures[2];
1638   unsigned int *features[2];
1641 #define OTF_SYM_TAG(SYM, TAG)                                   \
1642   do {                                                          \
1643     unsigned char *p = SDATA (SYMBOL_NAME (SYM));               \
1644     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1645   } while (0)
1647 #define OTF_TAG_STR(TAG, P)                     \
1648   do {                                          \
1649     (P)[0] = (char) (TAG >> 24);                \
1650     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1651     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1652     (P)[3] = (char) (TAG & 0xFF);               \
1653     (P)[4] = '\0';                              \
1654   } while (0)
1656 static struct OpenTypeSpec *
1657 macfont_get_open_type_spec (Lisp_Object otf_spec)
1659   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1660   Lisp_Object val;
1661   int i, j;
1662   bool negative;
1664   if (! spec)
1665     return NULL;
1666   spec->script = XCAR (otf_spec);
1667   if (! NILP (spec->script))
1668     {
1669       OTF_SYM_TAG (spec->script, spec->script_tag);
1670       val = assq_no_quit (spec->script, Votf_script_alist);
1671       if (CONSP (val) && SYMBOLP (XCDR (val)))
1672         spec->script = XCDR (val);
1673       else
1674         spec->script = Qnil;
1675     }
1676   else
1677     spec->script_tag = 0x44464C54;      /* "DFLT" */
1678   otf_spec = XCDR (otf_spec);
1679   spec->langsys_tag = 0;
1680   if (! NILP (otf_spec))
1681     {
1682       val = XCAR (otf_spec);
1683       if (! NILP (val))
1684         OTF_SYM_TAG (val, spec->langsys_tag);
1685       otf_spec = XCDR (otf_spec);
1686     }
1687   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1688   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1689     {
1690       Lisp_Object len;
1692       val = XCAR (otf_spec);
1693       if (NILP (val))
1694         continue;
1695       len = Flength (val);
1696       spec->features[i] =
1697         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1698          ? 0
1699          : malloc (XINT (len) * sizeof *spec->features[i]));
1700       if (! spec->features[i])
1701         {
1702           if (i > 0 && spec->features[0])
1703             free (spec->features[0]);
1704           free (spec);
1705           return NULL;
1706         }
1707       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1708         {
1709           if (NILP (XCAR (val)))
1710             negative = 1;
1711           else
1712             {
1713               unsigned int tag;
1715               OTF_SYM_TAG (XCAR (val), tag);
1716               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1717             }
1718         }
1719       spec->nfeatures[i] = j;
1720     }
1721   return spec;
1724 static CFMutableDictionaryRef
1725 macfont_create_attributes_with_spec (Lisp_Object spec)
1727   Lisp_Object tmp, extra;
1728   CFMutableArrayRef langarray = NULL;
1729   CFCharacterSetRef charset = NULL;
1730   CFStringRef charset_string = NULL;
1731   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1732   Lisp_Object script = Qnil;
1733   Lisp_Object registry;
1734   int cf_charset_idx, i;
1735   struct OpenTypeSpec *otspec = NULL;
1736   struct {
1737     enum font_property_index index;
1738     CFStringRef trait;
1739     CGPoint points[6];
1740   } numeric_traits[] =
1741       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1742         {{-0.4, 50},            /* light */
1743          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1744          {0, 100},              /* normal */
1745          {0.24, 140},           /* (semi-bold + normal) / 2 */
1746          {0.4, 200},            /* bold */
1747          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1748        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1749         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1750        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1751         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1753   registry = AREF (spec, FONT_REGISTRY_INDEX);
1754   if (NILP (registry)
1755       || EQ (registry, Qascii_0)
1756       || EQ (registry, Qiso10646_1)
1757       || EQ (registry, Qunicode_bmp))
1758     cf_charset_idx = -1;
1759   else
1760     {
1761       CFStringRef lang;
1763       cf_charset_idx = macfont_get_charset (registry);
1764       if (cf_charset_idx < 0)
1765         goto err;
1766       charset = cf_charset_table[cf_charset_idx].cf_charset;
1767       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1768       lang = cf_charset_table[cf_charset_idx].lang;
1769       if (lang)
1770         {
1771           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1772           if (! langarray)
1773             goto err;
1774           CFArrayAppendValue (langarray, lang);
1775         }
1776     }
1778   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1779        CONSP (extra); extra = XCDR (extra))
1780     {
1781       Lisp_Object key, val;
1783       tmp = XCAR (extra);
1784       key = XCAR (tmp), val = XCDR (tmp);
1785       if (EQ (key, QClang))
1786         {
1787           if (! langarray)
1788             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1789           if (! langarray)
1790             goto err;
1791           if (SYMBOLP (val))
1792             val = list1 (val);
1793           for (; CONSP (val); val = XCDR (val))
1794             if (SYMBOLP (XCAR (val)))
1795               {
1796                 CFStringRef lang =
1797                   cfstring_create_with_string_noencode (SYMBOL_NAME
1798                                                         (XCAR (val)));
1800                 if (lang == NULL)
1801                   goto err;
1802                 CFArrayAppendValue (langarray, lang);
1803                 CFRelease (lang);
1804               }
1805         }
1806       else if (EQ (key, QCotf))
1807         {
1808           otspec = macfont_get_open_type_spec (val);
1809           if (! otspec)
1810             goto err;
1811           script = otspec->script;
1812         }
1813       else if (EQ (key, QCscript))
1814         script = val;
1815     }
1817   if (! NILP (script) && ! charset)
1818     {
1819       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1821       if (CONSP (chars) && CONSP (CDR (chars)))
1822         {
1823           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1824           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1826           if (! string || !cs)
1827             {
1828               if (string)
1829                 CFRelease (string);
1830               else if (cs)
1831                 CFRelease (cs);
1832               goto err;
1833             }
1834           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1835             if (CHARACTERP (XCAR (chars)))
1836               {
1837                 UniChar unichars[2];
1838                 CFIndex count =
1839                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1840                                                        unichars);
1841                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1843                 CFStringAppendCharacters (string, unichars, count);
1844                 CFCharacterSetAddCharactersInRange (cs, range);
1845               }
1846           charset = cs;
1847           /* CFCharacterSetCreateWithCharactersInString does not
1848              handle surrogate pairs properly as of Mac OS X 10.5.  */
1849           charset_string = string;
1850         }
1851     }
1853   attributes = CFDictionaryCreateMutable (NULL, 0,
1854                                           &kCFTypeDictionaryKeyCallBacks,
1855                                           &kCFTypeDictionaryValueCallBacks);
1856   if (! attributes)
1857     goto err;
1859   tmp = AREF (spec, FONT_FAMILY_INDEX);
1860   if (SYMBOLP (tmp) && ! NILP (tmp))
1861     {
1862       CFStringRef family = macfont_create_family_with_symbol (tmp);
1864       if (! family)
1865         goto err;
1866       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1867                             family);
1868       CFRelease (family);
1869     }
1871   traits = CFDictionaryCreateMutable (NULL, 4,
1872                                       &kCFTypeDictionaryKeyCallBacks,
1873                                       &kCFTypeDictionaryValueCallBacks);
1874   if (! traits)
1875     goto err;
1877   for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); i++)
1878     {
1879       tmp = AREF (spec, numeric_traits[i].index);
1880       if (INTEGERP (tmp))
1881         {
1882           CGPoint *point = numeric_traits[i].points;
1883           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1884           CFNumberRef num;
1886           while (point->y < floatval)
1887             point++;
1888           if (point == numeric_traits[i].points)
1889             point++;
1890           else if (point->y == CGFLOAT_MAX)
1891             point--;
1892           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1893                                        * ((point->x - (point - 1)->x)
1894                                           / (point->y - (point - 1)->y)));
1895           if (floatval > 1.0)
1896             floatval = 1.0;
1897           else if (floatval < -1.0)
1898             floatval = -1.0;
1899           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1900           if (! num)
1901             goto err;
1902           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1903           CFRelease (num);
1904         }
1905     }
1906   if (CFDictionaryGetCount (traits))
1907     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1909   if (charset)
1910     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1911                           charset);
1912   if (charset_string)
1913     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1914                           charset_string);
1915   if (langarray)
1916     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1918   goto finish;
1920  err:
1921   if (attributes)
1922     {
1923       CFRelease (attributes);
1924       attributes = NULL;
1925     }
1927  finish:
1928   if (langarray) CFRelease (langarray);
1929   if (charset && cf_charset_idx < 0) CFRelease (charset);
1930   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1931   if (traits) CFRelease (traits);
1932   if (otspec)
1933     {
1934       if (otspec->nfeatures[0] > 0)
1935         free (otspec->features[0]);
1936       if (otspec->nfeatures[1] > 0)
1937         free (otspec->features[1]);
1938       free (otspec);
1939     }
1941   return attributes;
1944 static Boolean
1945 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1946                                           CFCharacterSetRef charset,
1947                                           Lisp_Object chars,
1948                                           CFArrayRef languages)
1950   Boolean result = true;
1952   if (charset || VECTORP (chars))
1953     {
1954       CFCharacterSetRef desc_charset =
1955         mac_font_descriptor_copy_attribute (desc,
1956                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1958       if (desc_charset == NULL)
1959         result = false;
1960       else
1961         {
1962           if (charset)
1963             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1964           else                  /* VECTORP (chars) */
1965             {
1966               ptrdiff_t j;
1968               for (j = 0; j < ASIZE (chars); j++)
1969                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
1970                     && CFCharacterSetIsLongCharacterMember (desc_charset,
1971                                                             XFASTINT (AREF (chars, j))))
1972                   break;
1973               if (j == ASIZE (chars))
1974                 result = false;
1975             }
1976           CFRelease (desc_charset);
1977         }
1978     }
1979   if (result && languages)
1980     result = mac_font_descriptor_supports_languages (desc, languages);
1982   return result;
1985 static CFIndex
1986 macfont_closest_traits_index (CFArrayRef traits_array,
1987                               FontSymbolicTraits target)
1989   CFIndex i, result = -1, count = CFArrayGetCount (traits_array);
1990   int min_distance = (1 << 3);
1992   for (i = 0; i < count; i++)
1993     {
1994       FontSymbolicTraits traits, diff;
1995       int distance = 0;
1997       traits = ((FontSymbolicTraits) (uintptr_t)
1998                 CFArrayGetValueAtIndex (traits_array, i));
1999       diff = (target ^ traits);
2000       /* We prefer synthetic bold of italic to synthetic italic of
2001          bold when both bold and italic are available but bold-italic
2002          is not available.  */
2003       if (diff & MAC_FONT_TRAIT_BOLD)
2004         distance |= (1 << 0);
2005       if (diff & MAC_FONT_TRAIT_ITALIC)
2006         distance |= (1 << 1);
2007       if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2008         distance |= (1 << 2);
2009       if (distance < min_distance)
2010         {
2011           min_distance = distance;
2012           result = i;
2013         }
2014     }
2016   return result;
2019 static Lisp_Object
2020 macfont_list (struct frame *f, Lisp_Object spec)
2022   Lisp_Object val = Qnil, family, extra;
2023   int i, n;
2024   CFStringRef family_name = NULL;
2025   CFMutableDictionaryRef attributes = NULL, traits;
2026   Lisp_Object chars = Qnil;
2027   int spacing = -1;
2028   FontSymbolicTraits synth_sym_traits = 0;
2029   CFArrayRef families;
2030   CFIndex families_count;
2031   CFCharacterSetRef charset = NULL;
2032   CFArrayRef languages = NULL;
2034   block_input ();
2036   family = AREF (spec, FONT_FAMILY_INDEX);
2037   if (! NILP (family))
2038     {
2039       family_name = macfont_create_family_with_symbol (family);
2040       if (family_name == NULL)
2041         goto finish;
2042     }
2044   attributes = macfont_create_attributes_with_spec (spec);
2045   if (! attributes)
2046     goto finish;
2048   charset = ((CFCharacterSetRef)
2049              CFDictionaryGetValue (attributes,
2050                                    MAC_FONT_CHARACTER_SET_ATTRIBUTE));
2051   if (charset)
2052     {
2053       CFRetain (charset);
2054       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2055     }
2056   else
2057     {
2058       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2059       if (! NILP (val))
2060         {
2061           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2062           if (CONSP (val) && VECTORP (XCDR (val)))
2063             chars = XCDR (val);
2064         }
2065       val = Qnil;
2066     }
2068   languages = ((CFArrayRef)
2069                CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE));
2070   if (languages)
2071     {
2072       CFRetain (languages);
2073       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2074     }
2076   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2077     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2079   traits = ((CFMutableDictionaryRef)
2080             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2082   n = FONT_SLANT_NUMERIC (spec);
2083   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2084     {
2085       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2086       if (traits)
2087         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2088     }
2090   n = FONT_WEIGHT_NUMERIC (spec);
2091   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2092     {
2093       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2094       if (traits)
2095         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2096     }
2098   if (languages
2099       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2100     {
2101       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2103       if (CFStringHasPrefix (language, CFSTR ("ja"))
2104           || CFStringHasPrefix (language, CFSTR ("ko"))
2105           || CFStringHasPrefix (language, CFSTR ("zh")))
2106         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2107     }
2109   /* Create array of families.  */
2110   if (family_name)
2111     families = CFArrayCreate (NULL, (const void **) &family_name,
2112                               1, &kCFTypeArrayCallBacks);
2113   else
2114     {
2115       CFStringRef pref_family;
2116       CFIndex families_count, pref_family_index = -1;
2118       families = mac_font_create_available_families ();
2119       if (families == NULL)
2120         goto err;
2122       families_count = CFArrayGetCount (families);
2124       /* Move preferred family to the front if exists.  */
2125       pref_family =
2126         mac_font_create_preferred_family_for_attributes (attributes);
2127       if (pref_family)
2128         {
2129           pref_family_index =
2130             CFArrayGetFirstIndexOfValue (families,
2131                                          CFRangeMake (0, families_count),
2132                                          pref_family);
2133           CFRelease (pref_family);
2134         }
2135       if (pref_family_index > 0)
2136         {
2137           CFMutableArrayRef mutable_families =
2138             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2140           if (mutable_families)
2141             {
2142               CFArrayAppendValue (mutable_families,
2143                                   CFArrayGetValueAtIndex (families,
2144                                                           pref_family_index));
2145               CFArrayAppendArray (mutable_families, families,
2146                                   CFRangeMake (0, pref_family_index));
2147               if (pref_family_index + 1 < families_count)
2148                 CFArrayAppendArray (mutable_families, families,
2149                                     CFRangeMake (pref_family_index + 1,
2150                                                  families_count
2151                                                  - (pref_family_index + 1)));
2152               CFRelease (families);
2153               families = mutable_families;
2154             }
2155         }
2156     }
2158   val = Qnil;
2159   extra = AREF (spec, FONT_EXTRA_INDEX);
2160   families_count = CFArrayGetCount (families);
2161   for (i = 0; i < families_count; i++)
2162     {
2163       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2164       FontDescriptorRef pat_desc;
2165       CFArrayRef descs;
2166       CFIndex descs_count;
2167       CFMutableArrayRef filtered_descs, traits_array;
2168       Lisp_Object entity;
2169       int j;
2171       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2172                             family_name);
2173       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2174       if (! pat_desc)
2175         goto err;
2177       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2178          10.7 returns NULL if pat_desc represents the LastResort font.
2179          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2180          trailing "s") for such a font.  */
2181       if (CFStringCompare (family_name, CFSTR ("LastResort"), 0)
2182           != kCFCompareEqualTo)
2183         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2184                                                                       NULL);
2185       else
2186         {
2187           FontDescriptorRef lr_desc =
2188             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2189                                                                  NULL);
2190           if (lr_desc)
2191             {
2192               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2193                                      &kCFTypeArrayCallBacks);
2194               CFRelease (lr_desc);
2195             }
2196           else
2197             descs = NULL;
2198         }
2199       CFRelease (pat_desc);
2200       if (! descs)
2201         goto err;
2203       descs_count = CFArrayGetCount (descs);
2204       if (descs_count == 0
2205           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2206                                                         charset, chars,
2207                                                         languages))
2208         {
2209           CFRelease (descs);
2210           continue;
2211         }
2213       filtered_descs =
2214         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2215       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2216       for (j = 0; j < descs_count; j++)
2217         {
2218           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2219           CFDictionaryRef dict;
2220           CFNumberRef num;
2221           FontSymbolicTraits sym_traits;
2223           dict = mac_font_descriptor_copy_attribute (desc,
2224                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2225           if (dict == NULL)
2226             continue;
2228           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2229           CFRelease (dict);
2230           if (num == NULL
2231               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2232             continue;
2234           if (spacing >= 0
2235               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2236               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2237                   != (spacing >= FONT_SPACING_MONO)))
2238             continue;
2240           /* Don't use a color bitmap font unless its family is
2241              explicitly specified.  */
2242           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2243             continue;
2245           if (j > 0
2246               && !macfont_supports_charset_and_languages_p (desc, charset,
2247                                                             chars, languages))
2248             continue;
2250           CFArrayAppendValue (filtered_descs, desc);
2251           CFArrayAppendValue (traits_array,
2252                               (const void *) (uintptr_t) sym_traits);
2253         }
2255       CFRelease (descs);
2256       descs = filtered_descs;
2257       descs_count = CFArrayGetCount (descs);
2259       for (j = 0; j < descs_count; j++)
2260         {
2261           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2262           FontSymbolicTraits sym_traits =
2263             ((FontSymbolicTraits) (uintptr_t)
2264              CFArrayGetValueAtIndex (traits_array, j));
2265           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2267           mask_min = ((synth_sym_traits ^ sym_traits)
2268                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2269           if (FONT_SLANT_NUMERIC (spec) < 0)
2270             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2271           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2272             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2274           mask_max = (synth_sym_traits & ~sym_traits);
2275           /* Synthetic bold does not work for bitmap-only fonts on Mac
2276              OS X 10.6.  */
2277           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2278             {
2279               CFNumberRef format =
2280                 mac_font_descriptor_copy_attribute (desc,
2281                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2283               if (format)
2284                 {
2285                   uint32_t format_val;
2287                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2288                                         &format_val)
2289                       && format_val == MAC_FONT_FORMAT_BITMAP)
2290                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2291                 }
2292             }
2293           if (spacing >= 0)
2294             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2296           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2297                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2298                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2299             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2300                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2301                  bmask += MAC_FONT_TRAIT_BOLD)
2302               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2303                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2304                    imask += MAC_FONT_TRAIT_ITALIC)
2305                 {
2306                   FontSymbolicTraits synth = (imask | bmask | mmask);
2308                   if (synth == 0
2309                       || j == macfont_closest_traits_index (traits_array,
2310                                                             (sym_traits | synth)))
2311                     {
2312                       entity = macfont_descriptor_entity (desc, extra, synth);
2313                       if (! NILP (entity))
2314                         val = Fcons (entity, val);
2315                     }
2316                 }
2317         }
2319       CFRelease (traits_array);
2320       CFRelease (descs);
2321     }
2323   CFRelease (families);
2324   val = Fnreverse (val);
2325   goto finish;
2326  err:
2327   val = Qnil;
2329  finish:
2330   FONT_ADD_LOG ("macfont-list", spec, val);
2331   if (charset) CFRelease (charset);
2332   if (languages) CFRelease (languages);
2333   if (attributes) CFRelease (attributes);
2334   if (family_name) CFRelease (family_name);
2336   unblock_input ();
2338   return val;
2341 static Lisp_Object
2342 macfont_match (struct frame * frame, Lisp_Object spec)
2344   Lisp_Object entity = Qnil;
2345   CFMutableDictionaryRef attributes;
2346   FontDescriptorRef pat_desc = NULL, desc = NULL;
2348   block_input ();
2350   attributes = macfont_create_attributes_with_spec (spec);
2351   if (attributes)
2352     {
2353       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2354       CFRelease (attributes);
2355     }
2356   if (pat_desc)
2357     {
2358       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2359                                                                   NULL);
2360       CFRelease (pat_desc);
2361     }
2362   if (desc)
2363     {
2364       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2365                                           0);
2366       CFRelease (desc);
2367     }
2368   unblock_input ();
2370   FONT_ADD_LOG ("macfont-match", spec, entity);
2371   return entity;
2374 static Lisp_Object
2375 macfont_list_family (struct frame *frame)
2377   Lisp_Object list = Qnil;
2378   CFArrayRef families;
2380   block_input ();
2382   families = mac_font_create_available_families ();
2383   if (families)
2384     {
2385       CFIndex i, count = CFArrayGetCount (families);
2387       for (i = 0; i < count; i++)
2388         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2389       CFRelease (families);
2390     }
2392   unblock_input ();
2394   return list;
2397 static void
2398 macfont_free_entity (Lisp_Object entity)
2400   Lisp_Object val = assq_no_quit (QCfont_entity,
2401                                   AREF (entity, FONT_EXTRA_INDEX));
2402   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2404   block_input ();
2405   CFRelease (name);
2406   unblock_input ();
2409 static Lisp_Object
2410 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2412   Lisp_Object val, font_object;
2413   CFStringRef font_name;
2414   struct macfont_info *macfont_info = NULL;
2415   struct font *font;
2416   int size;
2417   FontRef macfont;
2418   FontSymbolicTraits sym_traits;
2419   char name[256];
2420   int len, i, total_width;
2421   CGGlyph glyph;
2422   CGFloat ascent, descent, leading;
2424   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2425   if (! CONSP (val)
2426       || XTYPE (XCDR (val)) != Lisp_Misc
2427       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2428     return Qnil;
2429   font_name = XSAVE_POINTER (XCDR (val), 0);
2430   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2432   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2433   if (size == 0)
2434     size = pixel_size;
2436   block_input ();
2437   macfont = mac_font_create_with_name (font_name, size);
2438   if (macfont)
2439     {
2440       int fontsize = (int) [((NSFont *) macfont) pointSize];
2441       if (fontsize != size) size = fontsize;
2442     }
2443   unblock_input ();
2444   if (! macfont)
2445     return Qnil;
2447   font_object = font_make_object (VECSIZE (struct macfont_info), entity, size);
2448   ASET (font_object, FONT_TYPE_INDEX, macfont_driver.type);
2449   len = font_unparse_xlfd (entity, size, name, 256);
2450   if (len > 0)
2451     ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
2452   len = font_unparse_fcname (entity, size, name, 256);
2453   if (len > 0)
2454     ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
2455   else
2456     ASET (font_object, FONT_FULLNAME_INDEX,
2457           AREF (font_object, FONT_NAME_INDEX));
2458   font = XFONT_OBJECT (font_object);
2459   font->pixel_size = size;
2460   font->driver = &macfont_driver;
2461   font->encoding_charset = font->repertory_charset = -1;
2463   block_input ();
2465   macfont_info = (struct macfont_info *) font;
2466   macfont_info->macfont = macfont;
2467   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2468   
2469   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2470   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2471     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2472                                                                   size);
2473   else
2474     macfont_info->screen_font = NULL;
2475   macfont_info->cache = macfont_lookup_cache (font_name);
2476   macfont_retain_cache (macfont_info->cache);
2477   macfont_info->metrics = NULL;
2478   macfont_info->metrics_nrows = 0;
2479   macfont_info->synthetic_italic_p = 0;
2480   macfont_info->synthetic_bold_p = 0;
2481   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2482   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2483   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2484       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2485     macfont_info->synthetic_italic_p = 1;
2486   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2487       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2488     macfont_info->synthetic_bold_p = 1;
2489   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2490     macfont_info->spacing = MACFONT_SPACING_MONO;
2491   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2492            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2493                == FONT_SPACING_SYNTHETIC_MONO))
2494     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2495   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2496     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2497   else
2498     {
2499       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2500       if (CONSP (val))
2501         macfont_info->antialias =
2502           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2503     }
2504   macfont_info->color_bitmap_p = 0;
2505   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2506     macfont_info->color_bitmap_p = 1;
2508   glyph = macfont_get_glyph_for_character (font, ' ');
2509   if (glyph != kCGFontIndexInvalid)
2510     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2511   else
2512     /* dirty workaround */
2513     font->space_width = pixel_size;
2515   total_width = font->space_width;
2516   for (i = 1; i < 95; i++)
2517     {
2518       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2519       if (glyph == kCGFontIndexInvalid)
2520         break;
2521       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2522     }
2523   if (i == 95)
2524     font->average_width = total_width / 95;
2525   else
2526     font->average_width = font->space_width; /* XXX */
2528   if (!(macfont_info->screen_font
2529         && mac_screen_font_get_metrics (macfont_info->screen_font,
2530                                         &ascent, &descent, &leading)))
2531     {
2532       CFStringRef family_name;
2534       ascent = mac_font_get_ascent (macfont);
2535       descent = mac_font_get_descent (macfont);
2536       leading = mac_font_get_leading (macfont);
2537       /* AppKit and WebKit do some adjustment to the heights of
2538          Courier, Helvetica, and Times.  */
2539       family_name = mac_font_copy_family_name (macfont);
2540       if (family_name)
2541         {
2542           if ((CFStringCompare (family_name, CFSTR ("Courier"), 0)
2543                == kCFCompareEqualTo)
2544               || (CFStringCompare (family_name, CFSTR ("Helvetica"), 0)
2545                   == kCFCompareEqualTo)
2546               || (CFStringCompare (family_name, CFSTR ("Times"), 0)
2547                   == kCFCompareEqualTo))
2548             ascent += (ascent + descent) * .15f;
2549           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2550             {
2551               leading *= .25f;
2552               ascent += leading;
2553             }
2554           CFRelease (family_name);
2555         }
2556     }
2557   font->ascent = ascent + 0.5f;
2558   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2559   if (CONSP (val) && !NILP (XCDR (val)))
2560     font->descent = descent + 0.5f;
2561   else
2562     font->descent = descent + leading + 0.5f;
2563   font->height = font->ascent + font->descent;
2565   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2566   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2568   unblock_input ();
2570   /* Unfortunately Xft doesn't provide a way to get minimum char
2571      width.  So, we use space_width instead.  */
2572   font->min_width = font->max_width = font->space_width; /* XXX */
2574   font->baseline_offset = 0;
2575   font->relative_compose = 0;
2576   font->default_ascent = 0;
2577   font->vertical_centering = 0;
2579   return font_object;
2582 static void
2583 macfont_close (struct frame * f, struct font *font)
2585   struct macfont_info *macfont_info = (struct macfont_info *) font;
2586   int i;
2588   block_input ();
2589   CFRelease (macfont_info->macfont);
2590   CGFontRelease (macfont_info->cgfont);
2591   if (macfont_info->screen_font)
2592     CFRelease (macfont_info->screen_font);
2593   macfont_release_cache (macfont_info->cache);
2594   for (i = 0; i < macfont_info->metrics_nrows; i++)
2595     if (macfont_info->metrics[i])
2596       xfree (macfont_info->metrics[i]);
2597   if (macfont_info->metrics)
2598     xfree (macfont_info->metrics);
2599   unblock_input ();
2602 static int
2603 macfont_has_char (Lisp_Object font, int c)
2605   int result;
2606   CFCharacterSetRef charset;
2608   block_input ();
2609   if (FONT_ENTITY_P (font))
2610     {
2611       Lisp_Object val;
2612       CFStringRef name;
2614       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2615       val = XCDR (val);
2616       name = XSAVE_POINTER (val, 0);
2617       charset = macfont_get_cf_charset_for_name (name);
2618     }
2619   else
2620     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2622   result = CFCharacterSetIsLongCharacterMember (charset, c);
2623   unblock_input ();
2625   return result;
2628 static unsigned
2629 macfont_encode_char (struct font *font, int c)
2631   struct macfont_info *macfont_info = (struct macfont_info *) font;
2632   CGGlyph glyph;
2634   block_input ();
2635   glyph = macfont_get_glyph_for_character (font, c);
2636   unblock_input ();
2638   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2641 static int
2642 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2643                       struct font_metrics *metrics)
2645   int width, i;
2647   block_input ();
2648   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2649   for (i = 1; i < nglyphs; i++)
2650     {
2651       struct font_metrics m;
2652       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2653                                      NULL, 0);
2655       if (metrics)
2656         {
2657           if (width + m.lbearing < metrics->lbearing)
2658             metrics->lbearing = width + m.lbearing;
2659           if (width + m.rbearing > metrics->rbearing)
2660             metrics->rbearing = width + m.rbearing;
2661           if (m.ascent > metrics->ascent)
2662             metrics->ascent = m.ascent;
2663           if (m.descent > metrics->descent)
2664             metrics->descent = m.descent;
2665         }
2666       width += w;
2667     }
2668   unblock_input ();
2670   if (metrics) 
2671     metrics->width = width;
2673   return width;
2676 static int
2677 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2678               bool with_background)
2680   struct frame * f = s->f;
2681   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2682   FontRef macfont = macfont_info->macfont;
2683   CGContextRef context;
2684   BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2685   int end = isComposite ? s->cmp_to : s->nchars;
2686   int len = end - s->cmp_from;
2687   int i;
2689   block_input ();
2691   context = [[NSGraphicsContext currentContext] graphicsPort];
2692   CGContextSaveGState (context);
2694 #if 0
2695   if (s->num_clips > 0)
2696     {
2697       CGRect clips[2];
2699       for (i = 0; i < s->num_clips; i++)
2700         clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2701                                   s->clip[i].right - s->clip[i].left,
2702                                   s->clip[i].bottom - s->clip[i].top);
2703       CGContextClipToRects (context, clips, s->num_clips);
2704     }
2705 #endif
2707   if (with_background)
2708     {
2709       CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, s);
2710       CGContextFillRect (context,
2711                          CGRectMake (x, y,
2712                                      s->width, FONT_HEIGHT (s->font)));
2713     }
2715   if (macfont_info->cgfont)
2716     {
2717       CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2718       CGPoint *positions = alloca (sizeof (CGPoint) * len);
2719       CGFloat total_width = 0;
2720       CGFloat font_size = mac_font_get_size (macfont);
2721       CGAffineTransform atfm;
2722       CGFloat advance_delta = 0;
2723       int y_draw = -s->ybase;
2724       int no_antialias_p =
2725         (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2726          || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2727              && font_size <= macfont_antialias_threshold));
2729       for (i = 0; i < len; i++)
2730         {
2731           int width;
2733           glyphs[i] = *(s->char2b + s->cmp_from + i);
2734           width = (s->padding_p ? 1
2735                    : macfont_glyph_extents (s->font, glyphs[i],
2736                                             NULL, &advance_delta,
2737                                             no_antialias_p));
2738           positions[i].x = total_width + advance_delta;
2739           positions[i].y = 0;
2740           total_width += width;
2741         }
2743       CGContextScaleCTM (context, 1, -1);
2744       CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, s);
2745       if (macfont_info->synthetic_italic_p)
2746         atfm = synthetic_italic_atfm;
2747       else
2748         atfm = CGAffineTransformIdentity;
2749       if (macfont_info->synthetic_bold_p)
2750         {
2751           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2752           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2753           CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, s);
2754         }
2755       if (no_antialias_p)
2756         CGContextSetShouldAntialias (context, false);
2758       CGContextSetTextMatrix (context, atfm);
2759       CGContextSetTextPosition (context, x, y_draw);
2761 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2762       if (macfont_info->color_bitmap_p
2763 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2764           && CTFontDrawGlyphs != NULL
2765 #endif
2766           )
2767         {
2768           if (len > 0)
2769             {
2770               CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2771             }
2772         }
2773       else
2774 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2775         {
2776           CGContextSetFont (context, macfont_info->cgfont);
2777           CGContextSetFontSize (context, font_size);
2778           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2779         }
2780     }
2782   CGContextRestoreGState (context);
2784   unblock_input ();
2786   return len;
2789 Lisp_Object
2790 macfont_shape (Lisp_Object lgstring)
2792   struct font *font;
2793   struct macfont_info *macfont_info;
2794   FontRef macfont;
2795   ptrdiff_t glyph_len, len, i, j;
2796   CFIndex nonbmp_len;
2797   UniChar *unichars;
2798   CFIndex *nonbmp_indices;
2799   CFStringRef string;
2800   CFIndex used = 0;
2801   struct mac_glyph_layout *glyph_layouts;
2803   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2804   macfont_info = (struct macfont_info *) font;
2805   macfont = macfont_info->macfont;
2807   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2808   nonbmp_len = 0;
2809   for (i = 0; i < glyph_len; i++)
2810     {
2811       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2813       if (NILP (lglyph))
2814         break;
2815       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2816         nonbmp_len++;
2817     }
2819   len = i;
2820   assume (len <= TYPE_MAXIMUM (EMACS_INT) - 2);
2822   if (INT_MAX / 2 < len)
2823     memory_full (SIZE_MAX);
2825   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2826   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2827   for (i = j = 0; i < len; i++)
2828     {
2829       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2831       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2832         {
2833           nonbmp_indices[j] = i + j;
2834           j++;
2835         }
2836     }
2837   nonbmp_indices[j] = len + j;  /* sentinel */
2839   block_input ();
2841   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2842                                                kCFAllocatorNull);
2843   if (string)
2844     {
2845       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2846       if (macfont_info->screen_font)
2847         used = mac_screen_font_shape (macfont_info->screen_font, string,
2848                                       glyph_layouts, glyph_len);
2849       else
2850         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2851       CFRelease (string);
2852     }
2854   unblock_input ();
2856   if (used == 0)
2857     return Qnil;
2859   block_input ();
2861   for (i = 0; i < used; i++)
2862     {
2863       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2864       struct mac_glyph_layout *gl = glyph_layouts + i;
2865       EMACS_INT from, to;
2866       struct font_metrics metrics;
2867       int xoff, yoff, wadjust;
2869       if (NILP (lglyph))
2870         {
2871           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2872           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2873         }
2875       from = gl->comp_range.location;
2876       /* Convert UTF-16 index to UTF-32.  */
2877       j = 0;
2878       while (nonbmp_indices[j] < from)
2879         j++;
2880       from -= j;
2881       LGLYPH_SET_FROM (lglyph, from);
2883       to = gl->comp_range.location + gl->comp_range.length;
2884       /* Convert UTF-16 index to UTF-32.  */
2885       while (nonbmp_indices[j] < to)
2886         j++;
2887       to -= j;
2888       LGLYPH_SET_TO (lglyph, to - 1);
2890       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2891          the composition is trivial.  */
2892       {
2893         UTF32Char c;
2895         if (unichars[gl->string_index] >= 0xD800
2896             && unichars[gl->string_index] < 0xDC00)
2897           c = (((unichars[gl->string_index] - 0xD800) << 10)
2898                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2899         else
2900           c = unichars[gl->string_index];
2901         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2902           c = 0;
2903         LGLYPH_SET_CHAR (lglyph, c);
2904       }
2906       {
2907         unsigned long cc = gl->glyph_id;
2908         LGLYPH_SET_CODE (lglyph, cc);
2909       }
2911       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2912       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2913       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2914       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2915       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2916       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2918       xoff = lround (gl->advance_delta);
2919       yoff = lround (- gl->baseline_delta);
2920       wadjust = lround (gl->advance);
2921       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2922         {
2923           Lisp_Object vec;
2925           vec = Fmake_vector (make_number (3), Qnil);
2926           ASET (vec, 0, make_number (xoff));
2927           ASET (vec, 1, make_number (yoff));
2928           ASET (vec, 2, make_number (wadjust));
2929           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2930         }
2931     }
2933   unblock_input ();
2935   return make_number (used);
2938 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2939 typedef UInt8 UINT24[3];
2941 #pragma pack(push, 1)
2942 struct variation_selector_record
2944   UINT24 var_selector;
2945   UInt32 default_uvs_offset, non_default_uvs_offset;
2947 struct uvs_table
2949   UInt16 format;
2950   UInt32 length, num_var_selector_records;
2951   struct variation_selector_record variation_selector_records[1];
2953 #define SIZEOF_UVS_TABLE_HEADER \
2954   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2956 struct unicode_value_range
2958   UINT24 start_unicode_value;
2959   UInt8 additional_count;
2961 struct default_uvs_table {
2962   UInt32 num_unicode_value_ranges;
2963   struct unicode_value_range unicode_value_ranges[1];
2965 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
2966   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2968 struct uvs_mapping
2970   UINT24 unicode_value;
2971   UInt16 glyph_id;
2973 struct non_default_uvs_table
2975   UInt32 num_uvs_mappings;
2976   struct uvs_mapping uvs_mappings[1];
2978 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
2979   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
2980 #pragma pack(pop)
2982 /* Read big endian values.  The argument LVAL must be an lvalue.  */
2983 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
2984    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
2985    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
2986 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
2987 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
2988 /* Succeeding one byte should also be accessible.  */
2989 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
2990 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
2992 /* Return UVS subtable for the specified FONT.  If the subtable is not
2993    found or ill-formated, then return NULL.  */
2995 static CFDataRef
2996 mac_font_copy_uvs_table (FontRef font)
2998   CFDataRef cmap_table, uvs_table = NULL;
3000   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3001   if (cmap_table)
3002     {
3003       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3004       struct uvs_table *uvs;
3005       struct variation_selector_record *records;
3006       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3008 #if __LP64__
3009       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3010         goto finish;
3011 #endif
3013       cmap_len = CFDataGetLength (cmap_table);
3014       if (sizeof_sfntCMapHeader > cmap_len)
3015         goto finish;
3017       ntables = BUINT16_VALUE (cmap->numTables);
3018       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3019                      / sizeof_sfntCMapEncoding))
3020         goto finish;
3022       for (i = 0; i < ntables; i++)
3023         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3024              == kFontUnicodePlatform)
3025             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3026                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3027           {
3028             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3029             break;
3030           }
3031       if (i == ntables
3032           || uvs_offset > cmap_len
3033           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3034         goto finish;
3036       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3037       uvs_len = BUINT32_VALUE (uvs->length);
3038       if (uvs_len > cmap_len - uvs_offset
3039           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3040         goto finish;
3042       if (BUINT16_VALUE (uvs->format) != 14)
3043         goto finish;
3045       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3046       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3047                       / sizeof (struct variation_selector_record)))
3048         goto finish;
3050       records = uvs->variation_selector_records;
3051       for (i = 0; i < nrecords; i++)
3052         {
3053           UInt32 default_uvs_offset, non_default_uvs_offset;
3055           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3056           if (default_uvs_offset)
3057             {
3058               struct default_uvs_table *default_uvs;
3059               UInt32 nranges;
3061               if (default_uvs_offset > uvs_len
3062                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3063                       > uvs_len - default_uvs_offset))
3064                 goto finish;
3066               default_uvs = ((struct default_uvs_table *)
3067                              ((UInt8 *) uvs + default_uvs_offset));
3068               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3069               if (nranges > ((uvs_len - default_uvs_offset
3070                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3071                              / sizeof (struct unicode_value_range)))
3072                 goto finish;
3073               /* Now 2 * nranges can't overflow, so we can safely use
3074                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3075                  mac_font_get_glyphs_for_variants.  */
3076             }
3078           non_default_uvs_offset =
3079             BUINT32_VALUE (records[i].non_default_uvs_offset);
3080           if (non_default_uvs_offset)
3081             {
3082               struct non_default_uvs_table *non_default_uvs;
3083               UInt32 nmappings;
3085               if (non_default_uvs_offset > uvs_len
3086                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3087                       > uvs_len - non_default_uvs_offset))
3088                 goto finish;
3090               non_default_uvs = ((struct non_default_uvs_table *)
3091                                  ((UInt8 *) uvs + non_default_uvs_offset));
3092               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3093               if (nmappings > ((uvs_len - non_default_uvs_offset
3094                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3095                                / sizeof (struct uvs_mapping)))
3096                 goto finish;
3097               /* Now 2 * nmappings can't overflow, so we can safely
3098                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3099                  in mac_font_get_glyphs_for_variants.  */
3100             }
3101         }
3103       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3105     finish:
3106       CFRelease (cmap_table);
3107     }
3109   return uvs_table;
3112 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3113    sequence consisting of the given base character C and each
3114    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3115    result (explained below) into the corresponding GLYPHS[i].  If the
3116    entry is found in the Default UVS Table, then the result is 0.  If
3117    the entry is found in the Non-Default UVS Table, then the result is
3118    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3119    elements in SELECTORS must be sorted in strictly increasing
3120    order.  */
3122 static void
3123 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3124                                   const UTF32Char selectors[], CGGlyph glyphs[],
3125                                   CFIndex count)
3127   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3128   struct variation_selector_record *records = uvs->variation_selector_records;
3129   CFIndex i;
3130   UInt32 ir, nrecords;
3131 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3132   dispatch_queue_t queue =
3133     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3134   dispatch_group_t group = dispatch_group_create ();
3135 #endif
3137   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3138   i = 0;
3139   ir = 0;
3140   while (i < count && ir < nrecords)
3141     {
3142       UInt32 default_uvs_offset, non_default_uvs_offset;
3144       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3145         {
3146           glyphs[i++] = kCGFontIndexInvalid;
3147           continue;
3148         }
3149       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3150         {
3151           ir++;
3152           continue;
3153         }
3155       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3156       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3157       non_default_uvs_offset =
3158         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3159 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3160       dispatch_group_async (group, queue, ^{
3161 #endif
3162           glyphs[i] = kCGFontIndexInvalid;
3164           if (default_uvs_offset)
3165             {
3166               struct default_uvs_table *default_uvs =
3167                 (struct default_uvs_table *) ((UInt8 *) uvs
3168                                               + default_uvs_offset);
3169               struct unicode_value_range *ranges =
3170                 default_uvs->unicode_value_ranges;
3171               UInt32 lo, hi;
3173               lo = 0;
3174               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3175               while (lo < hi)
3176                 {
3177                   UInt32 mid = (lo + hi) / 2;
3179                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3180                     hi = mid;
3181                   else
3182                     lo = mid + 1;
3183                 }
3184               if (hi > 0
3185                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3186                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3187                 glyphs[i] = 0;
3188             }
3190           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3191             {
3192               struct non_default_uvs_table *non_default_uvs =
3193                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3194                                                   + non_default_uvs_offset);
3195               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3196               UInt32 lo, hi;
3198               lo = 0;
3199               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3200               while (lo < hi)
3201                 {
3202                   UInt32 mid = (lo + hi) / 2;
3204                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3205                     hi = mid;
3206                   else
3207                     lo = mid + 1;
3208                 }
3209               if (hi > 0 &&
3210                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3211                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3212             }
3213 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3214         });
3215 #endif
3216       i++;
3217       ir++;
3218     }
3219   while (i < count)
3220     glyphs[i++] = kCGFontIndexInvalid;
3221 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3222   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3223   dispatch_release (group);
3224 #endif
3227 static int
3228 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3230   CFDataRef uvs_table;
3231   CharacterCollection uvs_collection;
3232   int i, n = 0;
3234   block_input ();
3235   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3237   if (uvs_table)
3238     {
3239       UTF32Char selectors[256];
3240       CGGlyph glyphs[256];
3242       for (i = 0; i < 16; i++)
3243         selectors[i] = 0xFE00 + i;
3244       for (; i < 256; i++)
3245         selectors[i] = 0xE0100 + (i - 16);
3246       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3247       for (i = 0; i < 256; i++)
3248         {
3249           CGGlyph glyph = glyphs[i];
3251           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3252               && glyph != kCGFontIndexInvalid)
3253             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3254           if (glyph == kCGFontIndexInvalid)
3255             variations[i] = 0;
3256           else
3257             {
3258               variations[i] = (glyph ? glyph
3259                                : macfont_get_glyph_for_character (font, c));
3260               n++;
3261             }
3262         }
3263     }
3264   unblock_input ();
3266   return n;
3269 static const char *const macfont_booleans[] = {
3270   ":antialias",
3271   ":minspace",
3272   NULL,
3275 static const char *const macfont_non_booleans[] = {
3276   ":lang",
3277   ":script",
3278   ":destination",
3279   NULL,
3282 static void
3283 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3285   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3288 static Boolean
3289 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3290                                           CFArrayRef languages)
3292   Boolean result = true;
3293   CFArrayRef desc_languages =
3294     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3296   if (desc_languages == NULL)
3297     result = false;
3298   else
3299     {
3300       CFIndex desc_languages_count, i, languages_count;
3302       desc_languages_count = CFArrayGetCount (desc_languages);
3303       languages_count = CFArrayGetCount (languages);
3304       for (i = 0; i < languages_count; i++)
3305         if (!CFArrayContainsValue (desc_languages,
3306                                    CFRangeMake (0, desc_languages_count),
3307                                    CFArrayGetValueAtIndex (languages, i)))
3308           {
3309             result = false;
3310             break;
3311           }
3312       CFRelease (desc_languages);
3313     }
3315   return result;
3318 static CFStringRef
3319 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3321   CFStringRef result = NULL;
3322   CFStringRef charset_string =
3323     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3325   if (charset_string && CFStringGetLength (charset_string) > 0)
3326     {
3327       CFAttributedStringRef attr_string = NULL;
3328       CTLineRef ctline = NULL;
3329       CFDictionaryRef attrs =
3330         CFDictionaryCreate (NULL, NULL, NULL, 0,
3331                             &kCFTypeDictionaryKeyCallBacks,
3332                             &kCFTypeDictionaryValueCallBacks);
3334       if (attrs)
3335         {
3336           attr_string = CFAttributedStringCreate (NULL, charset_string, attrs);
3337           CFRelease (attrs);
3338         }
3339       if (attr_string)
3340         {
3341           ctline = CTLineCreateWithAttributedString (attr_string);
3342           CFRelease (attr_string);
3343         }
3344       if (ctline)
3345         {
3346           CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3347           CFIndex i, nruns = CFArrayGetCount (runs);
3348           CTFontRef font;
3350           for (i = 0; i < nruns; i++)
3351             {
3352               CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3353               CFDictionaryRef attributes = CTRunGetAttributes (run);
3354               CTFontRef font_in_run;
3356               if (attributes == NULL)
3357                 break;
3358               font_in_run =
3359                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3360               if (font_in_run == NULL)
3361                 break;
3362               if (i == 0)
3363                 font = font_in_run;
3364               else if (!mac_ctfont_equal_in_postscript_name (font, font_in_run))
3365                 break;
3366             }
3367           if (nruns > 0 && i == nruns)
3368             result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3369           CFRelease (ctline);
3370         }
3371     }
3373   return result;
3376 static inline double
3377 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3379   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3380                                      &glyph, NULL, 1);
3383 static inline CGRect
3384 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3386   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3387                                           &glyph, NULL, 1);
3390 static CFArrayRef
3391 mac_ctfont_create_available_families (void)
3393   CFMutableArrayRef families = NULL;
3395 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3396 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3397   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3398 #endif
3399     {
3400       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3402       if (orig_families)
3403         {
3404           CFIndex i, count = CFArrayGetCount (orig_families);
3406           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3407           if (families)
3408             for (i = 0; i < count; i++)
3409               {
3410                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3412                 if (!CFStringHasPrefix (family, CFSTR ("."))
3413                     && (CTFontManagerCompareFontFamilyNames (family,
3414                                                              CFSTR ("LastResort"),
3415                                                              NULL)
3416                         != kCFCompareEqualTo))
3417                   CFArrayAppendValue (families, family);
3418               }
3419           CFRelease (orig_families);
3420         }
3421     }
3422 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3423   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3424 #endif
3425 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3426 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3427     {
3428       CTFontCollectionRef collection;
3429       CFArrayRef descs = NULL;
3431       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3432       if (collection)
3433         {
3434           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3435           CFRelease (collection);
3436         }
3437       if (descs)
3438         {
3439           CFIndex i, count = CFArrayGetCount (descs);
3441           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3442           if (families)
3443             for (i = 0; i < count; i++)
3444               {
3445                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3446                 CFStringRef name =
3447                   mac_font_descriptor_copy_attribute (desc,
3448                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3450                 if (name)
3451                   {
3452                     CFIndex p, limit = CFArrayGetCount (families);
3454                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3455                                               (const void *) name,
3456                                               mac_font_family_compare, NULL);
3457                     if (p >= limit)
3458                       CFArrayAppendValue (families, name);
3459                     else if (mac_font_family_compare
3460                              (CFArrayGetValueAtIndex (families, p),
3461                               name, NULL) != kCFCompareEqualTo)
3462                       CFArrayInsertValueAtIndex (families, p, name);
3463                     CFRelease (name);
3464                   }
3465               }
3466           CFRelease (descs);
3467         }
3468     }
3469 #endif
3471   return families;
3474 static Boolean
3475 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3477   Boolean result;
3478   CFStringRef name1, name2;
3480   if (font1 == font2)
3481     return true;
3483   result = false;
3484   name1 = CTFontCopyPostScriptName (font1);
3485   if (name1)
3486     {
3487       name2 = CTFontCopyPostScriptName (font2);
3488       if (name2)
3489         {
3490           result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3491           CFRelease (name2);
3492         }
3493       CFRelease (name1);
3494     }
3496   return result;
3499 static CTLineRef
3500 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3501                                              CTFontRef macfont)
3503   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3504   CFTypeRef values[] = {NULL, NULL};
3505   CFDictionaryRef attributes = NULL;
3506   CFAttributedStringRef attr_string = NULL;
3507   CTLineRef ctline = NULL;
3508   float float_zero = 0.0f;
3510   values[0] = macfont;
3511   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3512   if (values[1])
3513     {
3514       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3515                                        (const void **) values,
3516                                        sizeof (keys) / sizeof (keys[0]),
3517                                        &kCFTypeDictionaryKeyCallBacks,
3518                                        &kCFTypeDictionaryValueCallBacks);
3519       CFRelease (values[1]);
3520     }
3521   if (attributes)
3522     {
3523       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3524       CFRelease (attributes);
3525     }
3526   if (attr_string)
3527     {
3528       ctline = CTLineCreateWithAttributedString (attr_string);
3529       CFRelease (attr_string);
3530     }
3531   if (ctline)
3532     {
3533       /* Abandon if ctline contains some fonts other than the
3534          specified one.  */
3535       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3536       CFIndex i, nruns = CFArrayGetCount (runs);
3538       for (i = 0; i < nruns; i++)
3539         {
3540           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3541           CFDictionaryRef attributes = CTRunGetAttributes (run);
3542           CTFontRef font_in_run;
3544           if (attributes == NULL)
3545             break;
3546           font_in_run =
3547             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3548           if (font_in_run == NULL)
3549             break;
3550           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3551             break;
3552         }
3553       if (i < nruns)
3554         {
3555           CFRelease (ctline);
3556           ctline = NULL;
3557         }
3558     }
3560   return ctline;
3563 CFIndex
3564 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3565                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3567   CFIndex used, result = 0;
3568   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3570   if (ctline == NULL)
3571     return 0;
3573   used = CTLineGetGlyphCount (ctline);
3574   if (used <= glyph_len)
3575     {
3576       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3577       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3578       CGFloat total_advance = 0;
3579       CFIndex total_glyph_count = 0;
3581       for (k = 0; k < ctrun_count; k++)
3582         {
3583           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3584           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3585           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3586           CFRange string_range, comp_range, range;
3587           CFIndex *permutation;
3589           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3590             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3591           else
3592             permutation = NULL;
3594 #define RIGHT_TO_LEFT_P permutation
3596           /* Now the `comp_range' member of struct mac_glyph_layout is
3597              temporarily used as a work area such that:
3598               glbuf[i].comp_range.location =
3599                 min {compRange[i + 1].location, ...,
3600                      compRange[glyph_count - 1].location,
3601                      maxRange (stringRangeForCTRun)}
3602               glbuf[i].comp_range.length = maxRange (compRange[i])
3603              where compRange[i] is the range of composed characters
3604              containing i-th glyph.  */
3605           string_range = CTRunGetStringRange (ctrun);
3606           min_location = string_range.location + string_range.length;
3607           for (i = 0; i < glyph_count; i++)
3608             {
3609               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3610               CFIndex glyph_index;
3611               CFRange rng;
3613               if (!RIGHT_TO_LEFT_P)
3614                 glyph_index = glyph_count - i - 1;
3615               else
3616                 glyph_index = i;
3617               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3618                                      &gl->string_index);
3619               rng =
3620                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3621                                                              gl->string_index);
3622               gl->comp_range.location = min_location;
3623               gl->comp_range.length = rng.location + rng.length;
3624               if (rng.location < min_location)
3625                 min_location = rng.location;
3626             }
3628           /* Fill the `comp_range' member of struct mac_glyph_layout,
3629              and setup a permutation for right-to-left text.  */
3630           comp_range = CFRangeMake (string_range.location, 0);
3631           range = CFRangeMake (0, 0);
3632           while (1)
3633             {
3634               struct mac_glyph_layout *gl =
3635                 glbuf + range.location + range.length;
3637               if (gl->comp_range.length
3638                   > comp_range.location + comp_range.length)
3639                 comp_range.length = gl->comp_range.length - comp_range.location;
3640               min_location = gl->comp_range.location;
3641               range.length++;
3643               if (min_location >= comp_range.location + comp_range.length)
3644                 {
3645                   comp_range.length = min_location - comp_range.location;
3646                   for (i = 0; i < range.length; i++)
3647                     {
3648                       glbuf[range.location + i].comp_range = comp_range;
3649                       if (RIGHT_TO_LEFT_P)
3650                         permutation[range.location + i] =
3651                           range.location + range.length - i - 1;
3652                     }
3654                   comp_range = CFRangeMake (min_location, 0);
3655                   range.location += range.length;
3656                   range.length = 0;
3657                   if (range.location == glyph_count)
3658                     break;
3659                 }
3660             }
3662           /* Then fill the remaining members.  */
3663           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3664                range.location++)
3665             {
3666               struct mac_glyph_layout *gl;
3667               CGPoint position;
3669               if (!RIGHT_TO_LEFT_P)
3670                 gl = glbuf + range.location;
3671               else
3672                 {
3673                   CFIndex src, dest;
3675                   src = glyph_count - 1 - range.location;
3676                   dest = permutation[src];
3677                   gl = glbuf + dest;
3678                   if (src < dest)
3679                     {
3680                       CFIndex tmp = gl->string_index;
3682                       gl->string_index = glbuf[src].string_index;
3683                       glbuf[src].string_index = tmp;
3684                     }
3685                 }
3686               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3688               CTRunGetPositions (ctrun, range, &position);
3689               gl->advance_delta = position.x - total_advance;
3690               gl->baseline_delta = position.y;
3691               gl->advance = (gl->advance_delta
3692                              + CTRunGetTypographicBounds (ctrun, range,
3693                                                           NULL, NULL, NULL));
3694               total_advance += gl->advance;
3695             }
3697           if (RIGHT_TO_LEFT_P)
3698             xfree (permutation);
3700 #undef RIGHT_TO_LEFT_P
3702           total_glyph_count += glyph_count;
3703         }
3705       result = used;
3706     }
3707   CFRelease (ctline);
3709   return result;
3712 /* The function below seems to cause a memory leak for the CFString
3713    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3714    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3715 #if USE_CT_GLYPH_INFO
3716 CGGlyph
3717 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3718                               CGFontIndex cid)
3720   CGGlyph result = kCGFontIndexInvalid;
3721   UniChar characters[] = {0xfffd};
3722   CFStringRef string;
3723   CFAttributedStringRef attr_string = NULL;
3724   CTLineRef ctline = NULL;
3726   string = CFStringCreateWithCharacters (NULL, characters,
3727                                          sizeof (characters)
3728                                          / sizeof (characters[0]));
3729   if (string)
3730     {
3731       CTGlyphInfoRef glyph_info =
3732         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3733       CFDictionaryRef attributes = NULL;
3735       if (glyph_info)
3736         {
3737           CFStringRef keys[] = {kCTFontAttributeName,
3738                                 kCTGlyphInfoAttributeName};
3739           CFTypeRef values[] = {font, glyph_info};
3741           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3742                                            (const void **) values,
3743                                            sizeof (keys) / sizeof (keys[0]),
3744                                            &kCFTypeDictionaryKeyCallBacks,
3745                                            &kCFTypeDictionaryValueCallBacks);
3746           CFRelease (glyph_info);
3747         }
3748       if (attributes)
3749         {
3750           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3751           CFRelease (attributes);
3752         }
3753       CFRelease (string);
3754     }
3755   if (attr_string)
3756     {
3757       ctline = CTLineCreateWithAttributedString (attr_string);
3758       CFRelease (attr_string);
3759     }
3760   if (ctline)
3761     {
3762       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3764       if (CFArrayGetCount (runs) > 0)
3765         {
3766           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3767           CFDictionaryRef attributes = CTRunGetAttributes (run);
3769           if (attributes)
3770             {
3771               CTFontRef font_in_run =
3772                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3774               if (font_in_run
3775                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3776                 {
3777                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3778                   if (result >= CTFontGetGlyphCount (font))
3779                     result = kCGFontIndexInvalid;
3780                 }
3781             }
3782         }
3783       CFRelease (ctline);
3784     }
3786   return result;
3788 #endif
3790 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3791 static inline int
3792 mac_font_family_group (CFStringRef family)
3794   if (CFStringHasPrefix (family, CFSTR ("#")))
3795     return 2;
3796   else
3797     {
3798       CFRange range;
3800       range = CFStringFind (family, CFSTR ("Apple"),
3801                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3802       if (range.location != kCFNotFound)
3803         return 1;
3805       return 0;
3806     }
3809 CFComparisonResult
3810 mac_font_family_compare (const void *val1, const void *val2, void *context)
3812   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3813   int group1, group2;
3815   group1 = mac_font_family_group (family1);
3816   group2 = mac_font_family_group (family2);
3817   if (group1 < group2)
3818     return kCFCompareLessThan;
3819   if (group1 > group2)
3820     return kCFCompareGreaterThan;
3821   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3823 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3825 void *
3826 macfont_get_nsctfont (struct font *font)
3828   struct macfont_info *macfont_info = (struct macfont_info *) font;
3829   FontRef macfont = macfont_info->macfont;
3831   return (void *) macfont;
3834 void
3835 mac_register_font_driver (struct frame *f)
3837   register_font_driver (&macfont_driver, f);
3840 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3843 void
3844 syms_of_macfont (void)
3846 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3847   static struct font_driver mac_font_driver;
3849   DEFSYM (Qmac_ct, "mac-ct");
3850   macfont_driver.type = Qmac_ct;
3851   register_font_driver (&macfont_driver, NULL);
3853   DEFSYM (QCdestination, ":destination");
3854   DEFSYM (QCminspace, ":minspace");
3855 #endif