etc/TODO small updates
[emacs.git] / src / macfont.m
blob150aca0765114f30d9ab1075b2ea44c386795d5f
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 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 font *font)
2585   struct macfont_info *macfont_info = (struct macfont_info *) font;
2587   if (macfont_info->cache)
2588     {
2589       int i;
2591       block_input ();
2592       CFRelease (macfont_info->macfont);
2593       CGFontRelease (macfont_info->cgfont);
2594       if (macfont_info->screen_font)
2595         CFRelease (macfont_info->screen_font);
2596       macfont_release_cache (macfont_info->cache);
2597       macfont_info->cache = NULL;
2598       for (i = 0; i < macfont_info->metrics_nrows; i++)
2599         if (macfont_info->metrics[i])
2600           xfree (macfont_info->metrics[i]);
2601       if (macfont_info->metrics)
2602         xfree (macfont_info->metrics);
2603       unblock_input ();
2604     }
2607 static int
2608 macfont_has_char (Lisp_Object font, int c)
2610   int result;
2611   CFCharacterSetRef charset;
2613   block_input ();
2614   if (FONT_ENTITY_P (font))
2615     {
2616       Lisp_Object val;
2617       CFStringRef name;
2619       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2620       val = XCDR (val);
2621       name = XSAVE_POINTER (val, 0);
2622       charset = macfont_get_cf_charset_for_name (name);
2623     }
2624   else
2625     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2627   result = CFCharacterSetIsLongCharacterMember (charset, c);
2628   unblock_input ();
2630   return result;
2633 static unsigned
2634 macfont_encode_char (struct font *font, int c)
2636   struct macfont_info *macfont_info = (struct macfont_info *) font;
2637   CGGlyph glyph;
2639   block_input ();
2640   glyph = macfont_get_glyph_for_character (font, c);
2641   unblock_input ();
2643   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2646 static int
2647 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2648                       struct font_metrics *metrics)
2650   int width, i;
2652   block_input ();
2653   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2654   for (i = 1; i < nglyphs; i++)
2655     {
2656       struct font_metrics m;
2657       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2658                                      NULL, 0);
2660       if (metrics)
2661         {
2662           if (width + m.lbearing < metrics->lbearing)
2663             metrics->lbearing = width + m.lbearing;
2664           if (width + m.rbearing > metrics->rbearing)
2665             metrics->rbearing = width + m.rbearing;
2666           if (m.ascent > metrics->ascent)
2667             metrics->ascent = m.ascent;
2668           if (m.descent > metrics->descent)
2669             metrics->descent = m.descent;
2670         }
2671       width += w;
2672     }
2673   unblock_input ();
2675   if (metrics) 
2676     metrics->width = width;
2678   return width;
2681 static int
2682 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2683               bool with_background)
2685   struct frame * f = s->f;
2686   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2687   FontRef macfont = macfont_info->macfont;
2688   CGContextRef context;
2689   BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2690   int end = isComposite ? s->cmp_to : s->nchars;
2691   int len = end - s->cmp_from;
2692   int i;
2694   block_input ();
2696   context = [[NSGraphicsContext currentContext] graphicsPort];
2697   CGContextSaveGState (context);
2699 #if 0
2700   if (s->num_clips > 0)
2701     {
2702       CGRect clips[2];
2704       for (i = 0; i < s->num_clips; i++)
2705         clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2706                                   s->clip[i].right - s->clip[i].left,
2707                                   s->clip[i].bottom - s->clip[i].top);
2708       CGContextClipToRects (context, clips, s->num_clips);
2709     }
2710 #endif
2712   if (with_background)
2713     {
2714       CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, s);
2715       CGContextFillRect (context,
2716                          CGRectMake (x, y,
2717                                      s->width, FONT_HEIGHT (s->font)));
2718     }
2720   if (macfont_info->cgfont)
2721     {
2722       CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2723       CGPoint *positions = alloca (sizeof (CGPoint) * len);
2724       CGFloat total_width = 0;
2725       CGFloat font_size = mac_font_get_size (macfont);
2726       CGAffineTransform atfm;
2727       CGFloat advance_delta = 0;
2728       int y_draw = -s->ybase;
2729       int no_antialias_p =
2730         (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2731          || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2732              && font_size <= macfont_antialias_threshold));
2734       for (i = 0; i < len; i++)
2735         {
2736           int width;
2738           glyphs[i] = *(s->char2b + s->cmp_from + i);
2739           width = (s->padding_p ? 1
2740                    : macfont_glyph_extents (s->font, glyphs[i],
2741                                             NULL, &advance_delta,
2742                                             no_antialias_p));
2743           positions[i].x = total_width + advance_delta;
2744           positions[i].y = 0;
2745           total_width += width;
2746         }
2748       CGContextScaleCTM (context, 1, -1);
2749       CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, s);
2750       if (macfont_info->synthetic_italic_p)
2751         atfm = synthetic_italic_atfm;
2752       else
2753         atfm = CGAffineTransformIdentity;
2754       if (macfont_info->synthetic_bold_p)
2755         {
2756           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2757           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2758           CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, s);
2759         }
2760       if (no_antialias_p)
2761         CGContextSetShouldAntialias (context, false);
2763       CGContextSetTextMatrix (context, atfm);
2764       CGContextSetTextPosition (context, x, y_draw);
2766 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2767       if (macfont_info->color_bitmap_p
2768 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2769           && CTFontDrawGlyphs != NULL
2770 #endif
2771           )
2772         {
2773           if (len > 0)
2774             {
2775               CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2776             }
2777         }
2778       else
2779 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2780         {
2781           CGContextSetFont (context, macfont_info->cgfont);
2782           CGContextSetFontSize (context, font_size);
2783           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2784         }
2785     }
2787   CGContextRestoreGState (context);
2789   unblock_input ();
2791   return len;
2794 Lisp_Object
2795 macfont_shape (Lisp_Object lgstring)
2797   struct font *font;
2798   struct macfont_info *macfont_info;
2799   FontRef macfont;
2800   ptrdiff_t glyph_len, len, i, j;
2801   CFIndex nonbmp_len;
2802   UniChar *unichars;
2803   CFIndex *nonbmp_indices;
2804   CFStringRef string;
2805   CFIndex used = 0;
2806   struct mac_glyph_layout *glyph_layouts;
2808   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2809   macfont_info = (struct macfont_info *) font;
2810   macfont = macfont_info->macfont;
2812   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2813   nonbmp_len = 0;
2814   for (i = 0; i < glyph_len; i++)
2815     {
2816       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2818       if (NILP (lglyph))
2819         break;
2820       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2821         nonbmp_len++;
2822     }
2824   len = i;
2826   if (INT_MAX / 2 < len)
2827     memory_full (SIZE_MAX);
2829   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2830   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2831   for (i = j = 0; i < len; i++)
2832     {
2833       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2835       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2836         {
2837           nonbmp_indices[j] = i + j;
2838           j++;
2839         }
2840     }
2841   nonbmp_indices[j] = len + j;  /* sentinel */
2843   block_input ();
2845   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2846                                                kCFAllocatorNull);
2847   if (string)
2848     {
2849       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2850       if (macfont_info->screen_font)
2851         used = mac_screen_font_shape (macfont_info->screen_font, string,
2852                                       glyph_layouts, glyph_len);
2853       else
2854         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2855       CFRelease (string);
2856     }
2858   unblock_input ();
2860   if (used == 0)
2861     return Qnil;
2863   block_input ();
2865   for (i = 0; i < used; i++)
2866     {
2867       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2868       struct mac_glyph_layout *gl = glyph_layouts + i;
2869       EMACS_INT from, to;
2870       struct font_metrics metrics;
2871       int xoff, yoff, wadjust;
2873       if (NILP (lglyph))
2874         {
2875           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2876           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2877         }
2879       from = gl->comp_range.location;
2880       /* Convert UTF-16 index to UTF-32.  */
2881       j = 0;
2882       while (nonbmp_indices[j] < from)
2883         j++;
2884       from -= j;
2885       LGLYPH_SET_FROM (lglyph, from);
2887       to = gl->comp_range.location + gl->comp_range.length;
2888       /* Convert UTF-16 index to UTF-32.  */
2889       while (nonbmp_indices[j] < to)
2890         j++;
2891       to -= j;
2892       LGLYPH_SET_TO (lglyph, to - 1);
2894       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2895          the composition is trivial.  */
2896       {
2897         UTF32Char c;
2899         if (unichars[gl->string_index] >= 0xD800
2900             && unichars[gl->string_index] < 0xDC00)
2901           c = (((unichars[gl->string_index] - 0xD800) << 10)
2902                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2903         else
2904           c = unichars[gl->string_index];
2905         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2906           c = 0;
2907         LGLYPH_SET_CHAR (lglyph, c);
2908       }
2910       {
2911         unsigned long cc = gl->glyph_id;
2912         LGLYPH_SET_CODE (lglyph, cc);
2913       }
2915       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2916       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2917       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2918       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2919       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2920       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2922       xoff = lround (gl->advance_delta);
2923       yoff = lround (- gl->baseline_delta);
2924       wadjust = lround (gl->advance);
2925       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2926         {
2927           Lisp_Object vec;
2929           vec = Fmake_vector (make_number (3), Qnil);
2930           ASET (vec, 0, make_number (xoff));
2931           ASET (vec, 1, make_number (yoff));
2932           ASET (vec, 2, make_number (wadjust));
2933           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2934         }
2935     }
2937   unblock_input ();
2939   return make_number (used);
2942 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2943 typedef UInt8 UINT24[3];
2945 #pragma pack(push, 1)
2946 struct variation_selector_record
2948   UINT24 var_selector;
2949   UInt32 default_uvs_offset, non_default_uvs_offset;
2951 struct uvs_table
2953   UInt16 format;
2954   UInt32 length, num_var_selector_records;
2955   struct variation_selector_record variation_selector_records[1];
2957 #define SIZEOF_UVS_TABLE_HEADER \
2958   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2960 struct unicode_value_range
2962   UINT24 start_unicode_value;
2963   UInt8 additional_count;
2965 struct default_uvs_table {
2966   UInt32 num_unicode_value_ranges;
2967   struct unicode_value_range unicode_value_ranges[1];
2969 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
2970   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2972 struct uvs_mapping
2974   UINT24 unicode_value;
2975   UInt16 glyph_id;
2977 struct non_default_uvs_table
2979   UInt32 num_uvs_mappings;
2980   struct uvs_mapping uvs_mappings[1];
2982 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
2983   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
2984 #pragma pack(pop)
2986 /* Read big endian values.  The argument LVAL must be an lvalue.  */
2987 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
2988    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
2989    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
2990 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
2991 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
2992 /* Succeeding one byte should also be accessible.  */
2993 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
2994 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
2996 /* Return UVS subtable for the specified FONT.  If the subtable is not
2997    found or ill-formated, then return NULL.  */
2999 static CFDataRef
3000 mac_font_copy_uvs_table (FontRef font)
3002   CFDataRef cmap_table, uvs_table = NULL;
3004   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3005   if (cmap_table)
3006     {
3007       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3008       struct uvs_table *uvs;
3009       struct variation_selector_record *records;
3010       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3012 #if __LP64__
3013       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3014         goto finish;
3015 #endif
3017       cmap_len = CFDataGetLength (cmap_table);
3018       if (sizeof_sfntCMapHeader > cmap_len)
3019         goto finish;
3021       ntables = BUINT16_VALUE (cmap->numTables);
3022       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3023                      / sizeof_sfntCMapEncoding))
3024         goto finish;
3026       for (i = 0; i < ntables; i++)
3027         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3028              == kFontUnicodePlatform)
3029             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3030                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3031           {
3032             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3033             break;
3034           }
3035       if (i == ntables
3036           || uvs_offset > cmap_len
3037           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3038         goto finish;
3040       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3041       uvs_len = BUINT32_VALUE (uvs->length);
3042       if (uvs_len > cmap_len - uvs_offset
3043           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3044         goto finish;
3046       if (BUINT16_VALUE (uvs->format) != 14)
3047         goto finish;
3049       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3050       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3051                       / sizeof (struct variation_selector_record)))
3052         goto finish;
3054       records = uvs->variation_selector_records;
3055       for (i = 0; i < nrecords; i++)
3056         {
3057           UInt32 default_uvs_offset, non_default_uvs_offset;
3059           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3060           if (default_uvs_offset)
3061             {
3062               struct default_uvs_table *default_uvs;
3063               UInt32 nranges;
3065               if (default_uvs_offset > uvs_len
3066                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3067                       > uvs_len - default_uvs_offset))
3068                 goto finish;
3070               default_uvs = ((struct default_uvs_table *)
3071                              ((UInt8 *) uvs + default_uvs_offset));
3072               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3073               if (nranges > ((uvs_len - default_uvs_offset
3074                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3075                              / sizeof (struct unicode_value_range)))
3076                 goto finish;
3077               /* Now 2 * nranges can't overflow, so we can safely use
3078                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3079                  mac_font_get_glyphs_for_variants.  */
3080             }
3082           non_default_uvs_offset =
3083             BUINT32_VALUE (records[i].non_default_uvs_offset);
3084           if (non_default_uvs_offset)
3085             {
3086               struct non_default_uvs_table *non_default_uvs;
3087               UInt32 nmappings;
3089               if (non_default_uvs_offset > uvs_len
3090                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3091                       > uvs_len - non_default_uvs_offset))
3092                 goto finish;
3094               non_default_uvs = ((struct non_default_uvs_table *)
3095                                  ((UInt8 *) uvs + non_default_uvs_offset));
3096               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3097               if (nmappings > ((uvs_len - non_default_uvs_offset
3098                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3099                                / sizeof (struct uvs_mapping)))
3100                 goto finish;
3101               /* Now 2 * nmappings can't overflow, so we can safely
3102                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3103                  in mac_font_get_glyphs_for_variants.  */
3104             }
3105         }
3107       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3109     finish:
3110       CFRelease (cmap_table);
3111     }
3113   return uvs_table;
3116 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3117    sequence consisting of the given base character C and each
3118    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3119    result (explained below) into the corresponding GLYPHS[i].  If the
3120    entry is found in the Default UVS Table, then the result is 0.  If
3121    the entry is found in the Non-Default UVS Table, then the result is
3122    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3123    elements in SELECTORS must be sorted in strictly increasing
3124    order.  */
3126 static void
3127 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3128                                   const UTF32Char selectors[], CGGlyph glyphs[],
3129                                   CFIndex count)
3131   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3132   struct variation_selector_record *records = uvs->variation_selector_records;
3133   CFIndex i;
3134   UInt32 ir, nrecords;
3135 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3136   dispatch_queue_t queue =
3137     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3138   dispatch_group_t group = dispatch_group_create ();
3139 #endif
3141   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3142   i = 0;
3143   ir = 0;
3144   while (i < count && ir < nrecords)
3145     {
3146       UInt32 default_uvs_offset, non_default_uvs_offset;
3148       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3149         {
3150           glyphs[i++] = kCGFontIndexInvalid;
3151           continue;
3152         }
3153       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3154         {
3155           ir++;
3156           continue;
3157         }
3159       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3160       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3161       non_default_uvs_offset =
3162         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3163 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3164       dispatch_group_async (group, queue, ^{
3165 #endif
3166           glyphs[i] = kCGFontIndexInvalid;
3168           if (default_uvs_offset)
3169             {
3170               struct default_uvs_table *default_uvs =
3171                 (struct default_uvs_table *) ((UInt8 *) uvs
3172                                               + default_uvs_offset);
3173               struct unicode_value_range *ranges =
3174                 default_uvs->unicode_value_ranges;
3175               UInt32 lo, hi;
3177               lo = 0;
3178               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3179               while (lo < hi)
3180                 {
3181                   UInt32 mid = (lo + hi) / 2;
3183                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3184                     hi = mid;
3185                   else
3186                     lo = mid + 1;
3187                 }
3188               if (hi > 0
3189                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3190                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3191                 glyphs[i] = 0;
3192             }
3194           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3195             {
3196               struct non_default_uvs_table *non_default_uvs =
3197                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3198                                                   + non_default_uvs_offset);
3199               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3200               UInt32 lo, hi;
3202               lo = 0;
3203               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3204               while (lo < hi)
3205                 {
3206                   UInt32 mid = (lo + hi) / 2;
3208                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3209                     hi = mid;
3210                   else
3211                     lo = mid + 1;
3212                 }
3213               if (hi > 0 &&
3214                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3215                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3216             }
3217 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3218         });
3219 #endif
3220       i++;
3221       ir++;
3222     }
3223   while (i < count)
3224     glyphs[i++] = kCGFontIndexInvalid;
3225 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3226   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3227   dispatch_release (group);
3228 #endif
3231 static int
3232 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3234   CFDataRef uvs_table;
3235   CharacterCollection uvs_collection;
3236   int i, n = 0;
3238   block_input ();
3239   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3241   if (uvs_table)
3242     {
3243       UTF32Char selectors[256];
3244       CGGlyph glyphs[256];
3246       for (i = 0; i < 16; i++)
3247         selectors[i] = 0xFE00 + i;
3248       for (; i < 256; i++)
3249         selectors[i] = 0xE0100 + (i - 16);
3250       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3251       for (i = 0; i < 256; i++)
3252         {
3253           CGGlyph glyph = glyphs[i];
3255           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3256               && glyph != kCGFontIndexInvalid)
3257             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3258           if (glyph == kCGFontIndexInvalid)
3259             variations[i] = 0;
3260           else
3261             {
3262               variations[i] = (glyph ? glyph
3263                                : macfont_get_glyph_for_character (font, c));
3264               n++;
3265             }
3266         }
3267     }
3268   unblock_input ();
3270   return n;
3273 static const char *const macfont_booleans[] = {
3274   ":antialias",
3275   ":minspace",
3276   NULL,
3279 static const char *const macfont_non_booleans[] = {
3280   ":lang",
3281   ":script",
3282   ":destination",
3283   NULL,
3286 static void
3287 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3289   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3292 static Boolean
3293 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3294                                           CFArrayRef languages)
3296   Boolean result = true;
3297   CFArrayRef desc_languages =
3298     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3300   if (desc_languages == NULL)
3301     result = false;
3302   else
3303     {
3304       CFIndex desc_languages_count, i, languages_count;
3306       desc_languages_count = CFArrayGetCount (desc_languages);
3307       languages_count = CFArrayGetCount (languages);
3308       for (i = 0; i < languages_count; i++)
3309         if (!CFArrayContainsValue (desc_languages,
3310                                    CFRangeMake (0, desc_languages_count),
3311                                    CFArrayGetValueAtIndex (languages, i)))
3312           {
3313             result = false;
3314             break;
3315           }
3316       CFRelease (desc_languages);
3317     }
3319   return result;
3322 static CFStringRef
3323 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3325   CFStringRef result = NULL;
3326   CFStringRef charset_string =
3327     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3329   if (charset_string && CFStringGetLength (charset_string) > 0)
3330     {
3331       CFAttributedStringRef attr_string = NULL;
3332       CTLineRef ctline = NULL;
3333       CFDictionaryRef attrs =
3334         CFDictionaryCreate (NULL, NULL, NULL, 0,
3335                             &kCFTypeDictionaryKeyCallBacks,
3336                             &kCFTypeDictionaryValueCallBacks);
3338       if (attrs)
3339         {
3340           attr_string = CFAttributedStringCreate (NULL, charset_string, attrs);
3341           CFRelease (attrs);
3342         }
3343       if (attr_string)
3344         {
3345           ctline = CTLineCreateWithAttributedString (attr_string);
3346           CFRelease (attr_string);
3347         }
3348       if (ctline)
3349         {
3350           CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3351           CFIndex i, nruns = CFArrayGetCount (runs);
3352           CTFontRef font;
3354           for (i = 0; i < nruns; i++)
3355             {
3356               CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3357               CFDictionaryRef attributes = CTRunGetAttributes (run);
3358               CTFontRef font_in_run;
3360               if (attributes == NULL)
3361                 break;
3362               font_in_run =
3363                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3364               if (font_in_run == NULL)
3365                 break;
3366               if (i == 0)
3367                 font = font_in_run;
3368               else if (!mac_ctfont_equal_in_postscript_name (font, font_in_run))
3369                 break;
3370             }
3371           if (nruns > 0 && i == nruns)
3372             result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3373           CFRelease (ctline);
3374         }
3375     }
3377   return result;
3380 static inline double
3381 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3383   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3384                                      &glyph, NULL, 1);
3387 static inline CGRect
3388 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3390   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3391                                           &glyph, NULL, 1);
3394 static CFArrayRef
3395 mac_ctfont_create_available_families (void)
3397   CFMutableArrayRef families = NULL;
3399 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3400 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3401   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3402 #endif
3403     {
3404       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3406       if (orig_families)
3407         {
3408           CFIndex i, count = CFArrayGetCount (orig_families);
3410           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3411           if (families)
3412             for (i = 0; i < count; i++)
3413               {
3414                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3416                 if (!CFStringHasPrefix (family, CFSTR ("."))
3417                     && (CTFontManagerCompareFontFamilyNames (family,
3418                                                              CFSTR ("LastResort"),
3419                                                              NULL)
3420                         != kCFCompareEqualTo))
3421                   CFArrayAppendValue (families, family);
3422               }
3423           CFRelease (orig_families);
3424         }
3425     }
3426 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3427   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3428 #endif
3429 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3430 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3431     {
3432       CTFontCollectionRef collection;
3433       CFArrayRef descs = NULL;
3435       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3436       if (collection)
3437         {
3438           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3439           CFRelease (collection);
3440         }
3441       if (descs)
3442         {
3443           CFIndex i, count = CFArrayGetCount (descs);
3445           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3446           if (families)
3447             for (i = 0; i < count; i++)
3448               {
3449                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3450                 CFStringRef name =
3451                   mac_font_descriptor_copy_attribute (desc,
3452                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3454                 if (name)
3455                   {
3456                     CFIndex p, limit = CFArrayGetCount (families);
3458                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3459                                               (const void *) name,
3460                                               mac_font_family_compare, NULL);
3461                     if (p >= limit)
3462                       CFArrayAppendValue (families, name);
3463                     else if (mac_font_family_compare
3464                              (CFArrayGetValueAtIndex (families, p),
3465                               name, NULL) != kCFCompareEqualTo)
3466                       CFArrayInsertValueAtIndex (families, p, name);
3467                     CFRelease (name);
3468                   }
3469               }
3470           CFRelease (descs);
3471         }
3472     }
3473 #endif
3475   return families;
3478 static Boolean
3479 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3481   Boolean result;
3482   CFStringRef name1, name2;
3484   if (font1 == font2)
3485     return true;
3487   result = false;
3488   name1 = CTFontCopyPostScriptName (font1);
3489   if (name1)
3490     {
3491       name2 = CTFontCopyPostScriptName (font2);
3492       if (name2)
3493         {
3494           result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3495           CFRelease (name2);
3496         }
3497       CFRelease (name1);
3498     }
3500   return result;
3503 static CTLineRef
3504 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3505                                              CTFontRef macfont)
3507   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3508   CFTypeRef values[] = {NULL, NULL};
3509   CFDictionaryRef attributes = NULL;
3510   CFAttributedStringRef attr_string = NULL;
3511   CTLineRef ctline = NULL;
3512   float float_zero = 0.0f;
3514   values[0] = macfont;
3515   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3516   if (values[1])
3517     {
3518       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3519                                        (const void **) values,
3520                                        sizeof (keys) / sizeof (keys[0]),
3521                                        &kCFTypeDictionaryKeyCallBacks,
3522                                        &kCFTypeDictionaryValueCallBacks);
3523       CFRelease (values[1]);
3524     }
3525   if (attributes)
3526     {
3527       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3528       CFRelease (attributes);
3529     }
3530   if (attr_string)
3531     {
3532       ctline = CTLineCreateWithAttributedString (attr_string);
3533       CFRelease (attr_string);
3534     }
3535   if (ctline)
3536     {
3537       /* Abandon if ctline contains some fonts other than the
3538          specified one.  */
3539       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3540       CFIndex i, nruns = CFArrayGetCount (runs);
3542       for (i = 0; i < nruns; i++)
3543         {
3544           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3545           CFDictionaryRef attributes = CTRunGetAttributes (run);
3546           CTFontRef font_in_run;
3548           if (attributes == NULL)
3549             break;
3550           font_in_run =
3551             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3552           if (font_in_run == NULL)
3553             break;
3554           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3555             break;
3556         }
3557       if (i < nruns)
3558         {
3559           CFRelease (ctline);
3560           ctline = NULL;
3561         }
3562     }
3564   return ctline;
3567 CFIndex
3568 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3569                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3571   CFIndex used, result = 0;
3572   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3574   if (ctline == NULL)
3575     return 0;
3577   used = CTLineGetGlyphCount (ctline);
3578   if (used <= glyph_len)
3579     {
3580       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3581       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3582       CGFloat total_advance = 0;
3583       CFIndex total_glyph_count = 0;
3585       for (k = 0; k < ctrun_count; k++)
3586         {
3587           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3588           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3589           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3590           CFRange string_range, comp_range, range;
3591           CFIndex *permutation;
3593           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3594             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3595           else
3596             permutation = NULL;
3598 #define RIGHT_TO_LEFT_P permutation
3600           /* Now the `comp_range' member of struct mac_glyph_layout is
3601              temporarily used as a work area such that:
3602               glbuf[i].comp_range.location =
3603                 min {compRange[i + 1].location, ...,
3604                      compRange[glyph_count - 1].location,
3605                      maxRange (stringRangeForCTRun)}
3606               glbuf[i].comp_range.length = maxRange (compRange[i])
3607              where compRange[i] is the range of composed characters
3608              containing i-th glyph.  */
3609           string_range = CTRunGetStringRange (ctrun);
3610           min_location = string_range.location + string_range.length;
3611           for (i = 0; i < glyph_count; i++)
3612             {
3613               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3614               CFIndex glyph_index;
3615               CFRange rng;
3617               if (!RIGHT_TO_LEFT_P)
3618                 glyph_index = glyph_count - i - 1;
3619               else
3620                 glyph_index = i;
3621               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3622                                      &gl->string_index);
3623               rng =
3624                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3625                                                              gl->string_index);
3626               gl->comp_range.location = min_location;
3627               gl->comp_range.length = rng.location + rng.length;
3628               if (rng.location < min_location)
3629                 min_location = rng.location;
3630             }
3632           /* Fill the `comp_range' member of struct mac_glyph_layout,
3633              and setup a permutation for right-to-left text.  */
3634           comp_range = CFRangeMake (string_range.location, 0);
3635           range = CFRangeMake (0, 0);
3636           while (1)
3637             {
3638               struct mac_glyph_layout *gl =
3639                 glbuf + range.location + range.length;
3641               if (gl->comp_range.length
3642                   > comp_range.location + comp_range.length)
3643                 comp_range.length = gl->comp_range.length - comp_range.location;
3644               min_location = gl->comp_range.location;
3645               range.length++;
3647               if (min_location >= comp_range.location + comp_range.length)
3648                 {
3649                   comp_range.length = min_location - comp_range.location;
3650                   for (i = 0; i < range.length; i++)
3651                     {
3652                       glbuf[range.location + i].comp_range = comp_range;
3653                       if (RIGHT_TO_LEFT_P)
3654                         permutation[range.location + i] =
3655                           range.location + range.length - i - 1;
3656                     }
3658                   comp_range = CFRangeMake (min_location, 0);
3659                   range.location += range.length;
3660                   range.length = 0;
3661                   if (range.location == glyph_count)
3662                     break;
3663                 }
3664             }
3666           /* Then fill the remaining members.  */
3667           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3668                range.location++)
3669             {
3670               struct mac_glyph_layout *gl;
3671               CGPoint position;
3673               if (!RIGHT_TO_LEFT_P)
3674                 gl = glbuf + range.location;
3675               else
3676                 {
3677                   CFIndex src, dest;
3679                   src = glyph_count - 1 - range.location;
3680                   dest = permutation[src];
3681                   gl = glbuf + dest;
3682                   if (src < dest)
3683                     {
3684                       CFIndex tmp = gl->string_index;
3686                       gl->string_index = glbuf[src].string_index;
3687                       glbuf[src].string_index = tmp;
3688                     }
3689                 }
3690               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3692               CTRunGetPositions (ctrun, range, &position);
3693               gl->advance_delta = position.x - total_advance;
3694               gl->baseline_delta = position.y;
3695               gl->advance = (gl->advance_delta
3696                              + CTRunGetTypographicBounds (ctrun, range,
3697                                                           NULL, NULL, NULL));
3698               total_advance += gl->advance;
3699             }
3701           if (RIGHT_TO_LEFT_P)
3702             xfree (permutation);
3704 #undef RIGHT_TO_LEFT_P
3706           total_glyph_count += glyph_count;
3707         }
3709       result = used;
3710     }
3711   CFRelease (ctline);
3713   return result;
3716 /* The function below seems to cause a memory leak for the CFString
3717    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3718    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3719 #if USE_CT_GLYPH_INFO
3720 CGGlyph
3721 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3722                               CGFontIndex cid)
3724   CGGlyph result = kCGFontIndexInvalid;
3725   UniChar characters[] = {0xfffd};
3726   CFStringRef string;
3727   CFAttributedStringRef attr_string = NULL;
3728   CTLineRef ctline = NULL;
3730   string = CFStringCreateWithCharacters (NULL, characters,
3731                                          sizeof (characters)
3732                                          / sizeof (characters[0]));
3733   if (string)
3734     {
3735       CTGlyphInfoRef glyph_info =
3736         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3737       CFDictionaryRef attributes = NULL;
3739       if (glyph_info)
3740         {
3741           CFStringRef keys[] = {kCTFontAttributeName,
3742                                 kCTGlyphInfoAttributeName};
3743           CFTypeRef values[] = {font, glyph_info};
3745           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3746                                            (const void **) values,
3747                                            sizeof (keys) / sizeof (keys[0]),
3748                                            &kCFTypeDictionaryKeyCallBacks,
3749                                            &kCFTypeDictionaryValueCallBacks);
3750           CFRelease (glyph_info);
3751         }
3752       if (attributes)
3753         {
3754           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3755           CFRelease (attributes);
3756         }
3757       CFRelease (string);
3758     }
3759   if (attr_string)
3760     {
3761       ctline = CTLineCreateWithAttributedString (attr_string);
3762       CFRelease (attr_string);
3763     }
3764   if (ctline)
3765     {
3766       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3768       if (CFArrayGetCount (runs) > 0)
3769         {
3770           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3771           CFDictionaryRef attributes = CTRunGetAttributes (run);
3773           if (attributes)
3774             {
3775               CTFontRef font_in_run =
3776                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3778               if (font_in_run
3779                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3780                 {
3781                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3782                   if (result >= CTFontGetGlyphCount (font))
3783                     result = kCGFontIndexInvalid;
3784                 }
3785             }
3786         }
3787       CFRelease (ctline);
3788     }
3790   return result;
3792 #endif
3794 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3795 static inline int
3796 mac_font_family_group (CFStringRef family)
3798   if (CFStringHasPrefix (family, CFSTR ("#")))
3799     return 2;
3800   else
3801     {
3802       CFRange range;
3804       range = CFStringFind (family, CFSTR ("Apple"),
3805                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3806       if (range.location != kCFNotFound)
3807         return 1;
3809       return 0;
3810     }
3813 CFComparisonResult
3814 mac_font_family_compare (const void *val1, const void *val2, void *context)
3816   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3817   int group1, group2;
3819   group1 = mac_font_family_group (family1);
3820   group2 = mac_font_family_group (family2);
3821   if (group1 < group2)
3822     return kCFCompareLessThan;
3823   if (group1 > group2)
3824     return kCFCompareGreaterThan;
3825   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3827 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3829 void *
3830 macfont_get_nsctfont (struct font *font)
3832   struct macfont_info *macfont_info = (struct macfont_info *) font;
3833   FontRef macfont = macfont_info->macfont;
3835   return (void *) macfont;
3838 void
3839 mac_register_font_driver (struct frame *f)
3841   register_font_driver (&macfont_driver, f);
3844 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3847 void
3848 syms_of_macfont (void)
3850 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3851   static struct font_driver mac_font_driver;
3853   DEFSYM (Qmac_ct, "mac-ct");
3854   macfont_driver.type = Qmac_ct;
3855   register_font_driver (&macfont_driver, NULL);
3857   DEFSYM (QCdestination, ":destination");
3858   DEFSYM (QCminspace, ":minspace");
3859 #endif