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