Doc tweaks re multi-monitor
[emacs.git] / src / macfont.m
blob69bde9f66a7dca67e9a011598eafea8f72427e85
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2014 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
22 #include <config.h>
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "frame.h"
27 #include "blockinput.h"
28 #include "character.h"
29 #include "charset.h"
30 #include "composite.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "termchar.h"
34 #include "nsgui.h"
35 #include "nsterm.h"
36 #include "macfont.h"
37 #include "macuvs.h"
39 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
41 #include <libkern/OSByteOrder.h>
43 static struct font_driver macfont_driver;
45 /* Core Text, for Mac OS X 10.5 and later.  */
46 static Lisp_Object Qmac_ct;
48 static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
49 static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
50 static CFArrayRef mac_ctfont_create_available_families (void);
51 static Boolean mac_ctfont_equal_in_postscript_name (CTFontRef, CTFontRef);
52 static CTLineRef mac_ctfont_create_line_with_string_and_font (CFStringRef,
53                                                               CTFontRef);
54 static CFComparisonResult mac_font_family_compare (const void *,
55                                                    const void *, void *);
56 static Boolean mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef,
57                                                          CFArrayRef);
58 static CFStringRef mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef);
59 static CFIndex mac_ctfont_shape (CTFontRef, CFStringRef,
60                                  struct mac_glyph_layout *, CFIndex);
61 static CFArrayRef
62 mac_font_copy_default_descriptors_for_language (CFStringRef language);
64 static CFStringRef
65 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
66                                                       CFArrayRef languages);
68 #if USE_CT_GLYPH_INFO
69 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef,
70                                              CTCharacterCollection,
71                                              CGFontIndex);
72 #endif
74 /* The font property key specifying the font design destination.  The
75    value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
76    text.  (See the documentation of X Logical Font Description
77    Conventions.)  In the Mac font driver, 1 means the screen font is
78    used for calculating some glyph metrics.  You can see the
79    difference with Monaco 8pt or 9pt, for example.  */
80 static Lisp_Object QCdestination;
82 /* The boolean-valued font property key specifying the use of
83    leading.  */
84 static Lisp_Object QCminspace;
86 struct macfont_metrics;
88 /* The actual structure for Mac font that can be cast to struct font.  */
90 struct macfont_info
92   struct font font;
93   FontRef macfont;
94   CGFontRef cgfont;
95   ScreenFontRef screen_font;
96   struct macfont_cache *cache;
97   struct macfont_metrics **metrics;
98   short metrics_nrows;
99   bool_bf synthetic_italic_p : 1;
100   bool_bf synthetic_bold_p : 1;
101   unsigned spacing : 2;
102   unsigned antialias : 2;
103   bool_bf color_bitmap_p : 1;
106 /* Values for the `spacing' member in `struct macfont_info'.  */
108 enum
109   {
110     MACFONT_SPACING_PROPORTIONAL,
111     MACFONT_SPACING_MONO,
112     MACFONT_SPACING_SYNTHETIC_MONO,
113   };
115 /* Values for the `antialias' member in `struct macfont_info'.  */
117 enum
118   {
119     MACFONT_ANTIALIAS_DEFAULT,
120     MACFONT_ANTIALIAS_OFF,
121     MACFONT_ANTIALIAS_ON,
122   };
124 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
125 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
126 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
128 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
129 static const CGFloat synthetic_bold_factor = 0.024;
131 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
132                                                         FontSymbolicTraits *);
133 static void macfont_store_descriptor_attributes (FontDescriptorRef,
134                                                  Lisp_Object);
135 static Lisp_Object macfont_descriptor_entity (FontDescriptorRef,
136                                               Lisp_Object,
137                                               FontSymbolicTraits);
138 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
139 static int macfont_glyph_extents (struct font *, CGGlyph,
140                                   struct font_metrics *, CGFloat *, int);
141 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
142 static Boolean macfont_supports_charset_and_languages_p (FontDescriptorRef,
143                                                          CFCharacterSetRef,
144                                                          Lisp_Object,
145                                                          CFArrayRef);
146 static CFIndex macfont_closest_traits_index (CFArrayRef,
147                                              FontSymbolicTraits);
148 static CFDataRef mac_font_copy_uvs_table (FontRef);
149 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
150                                               const UTF32Char [],
151                                               CGGlyph [], CFIndex);
153 /* From CFData to a lisp string.  Always returns a unibyte string.  */
155 static Lisp_Object
156 cfdata_to_lisp (CFDataRef data)
158   CFIndex len = CFDataGetLength (data);
159   Lisp_Object result = make_uninit_string (len);
161   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
163   return result;
168 /* From CFString to a lisp string.  Returns a unibyte string
169    containing a UTF-8 byte sequence.  */
171 static Lisp_Object
172 cfstring_to_lisp_nodecode (CFStringRef string)
174   Lisp_Object result = Qnil;
175   CFDataRef data;
176   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
178   if (s)
179     {
180       CFIndex i, length = CFStringGetLength (string);
182       for (i = 0; i < length; i++)
183         if (CFStringGetCharacterAtIndex (string, i) == 0)
184           break;
186       if (i == length)
187         return make_unibyte_string (s, strlen (s));
188     }
190   data = CFStringCreateExternalRepresentation (NULL, string,
191                                                kCFStringEncodingUTF8, '?');
192   if (data)
193     {
194       result = cfdata_to_lisp (data);
195       CFRelease (data);
196     }
198   return result;
201 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
202    cfstring_create_with_utf8_cstring, this function preserves NUL
203    characters.  */
205 static CFStringRef
206 cfstring_create_with_string_noencode (Lisp_Object s)
208   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
209                                                 kCFStringEncodingUTF8, false);
211   if (string == NULL)
212     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
213     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
214                                       kCFStringEncodingMacRoman, false);
216   return string;
219 static CGFloat
220 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
222   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
224   return advancement.width;
227 static CGGlyph
228 mac_font_get_glyph_for_cid (FontRef font, CharacterCollection collection,
229                             CGFontIndex cid)
231 #if USE_CT_GLYPH_INFO
232   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
233 #else
234   {
235     CGGlyph result = kCGFontIndexInvalid;
236     NSFont *nsFont = (NSFont *) font;
237     unichar characters[] = {0xfffd};
238     NSString *string =
239       [NSString stringWithCharacters:characters
240                               length:(sizeof (characters)
241                                       / sizeof (characters[0]))];
242     NSGlyphInfo *glyphInfo =
243       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
244                                          collection:collection
245                                          baseString:string];
246     NSDictionary *attributes =
247       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
248                     glyphInfo,NSGlyphInfoAttributeName,nil];
249     NSTextStorage *textStorage =
250       [[NSTextStorage alloc] initWithString:string
251                                  attributes:attributes];
252     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
253     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
254     NSFont *fontInTextStorage;
256     [layoutManager addTextContainer:textContainer];
257     [textContainer release];
258     [textStorage addLayoutManager:layoutManager];
259     [layoutManager release];
261     /* Force layout.  */
262     (void) [layoutManager glyphRangeForTextContainer:textContainer];
264     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
265                                 effectiveRange:NULL];
266     if (fontInTextStorage == nsFont
267         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
268       {
269         NSGlyph glyph = [layoutManager glyphAtIndex:0];
271         if (glyph < [nsFont numberOfGlyphs])
272           result = glyph;
273       }
275     [textStorage release];
277     return result;
278   }
280 #endif
282 static ScreenFontRef
283 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
285   NSFont *result, *font;
287   font = [NSFont fontWithName:((NSString *) name) size:size];
288   result = [font screenFont];
290   return (ScreenFontRef)[result retain];
294 static Boolean
295 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
296                              CGFloat *descent, CGFloat *leading)
298   NSFont *nsFont = [(NSFont *)font printerFont];
299   NSTextStorage *textStorage;
300   NSLayoutManager *layoutManager;
301   NSTextContainer *textContainer;
302   NSRect usedRect;
303   NSPoint spaceLocation;
304   CGFloat descender;
306   textStorage = [[NSTextStorage alloc] initWithString:@" "];
307   layoutManager = [[NSLayoutManager alloc] init];
308   textContainer = [[NSTextContainer alloc] init];
310   [textStorage setFont:nsFont];
311   [textContainer setLineFragmentPadding:0];
312   [layoutManager setUsesScreenFonts:YES];
314   [layoutManager addTextContainer:textContainer];
315   [textContainer release];
316   [textStorage addLayoutManager:layoutManager];
317   [layoutManager release];
319   if (!(textStorage && layoutManager && textContainer))
320     {
321       [textStorage release];
323       return false;
324     }
326   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
327                                                  effectiveRange:NULL];
328   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
329   [textStorage release];
331   *ascent = spaceLocation.y;
332   *descent = NSHeight (usedRect) - spaceLocation.y;
333   *leading = 0;
334   descender = [nsFont descender];
335   if (- descender < *descent)
336     {
337       *leading = *descent + descender;
338       *descent = - descender;
339     }
341   return true;
344 static CFIndex
345 mac_font_shape_1 (NSFont *font, NSString *string,
346                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
347                   BOOL screen_font_p)
349   NSUInteger i;
350   CFIndex result = 0;
351   NSTextStorage *textStorage;
352   NSLayoutManager *layoutManager;
353   NSTextContainer *textContainer;
354   NSUInteger stringLength;
355   NSPoint spaceLocation;
356   NSUInteger used, numberOfGlyphs;
358   textStorage = [[NSTextStorage alloc] initWithString:string];
359   layoutManager = [[NSLayoutManager alloc] init];
360   textContainer = [[NSTextContainer alloc] init];
362   /* Append a trailing space to measure baseline position.  */
363   [textStorage appendAttributedString:([[[NSAttributedString alloc]
364                                           initWithString:@" "] autorelease])];
365   [textStorage setFont:font];
366   [textContainer setLineFragmentPadding:0];
367   [layoutManager setUsesScreenFonts:screen_font_p];
369   [layoutManager addTextContainer:textContainer];
370   [textContainer release];
371   [textStorage addLayoutManager:layoutManager];
372   [layoutManager release];
374   if (!(textStorage && layoutManager && textContainer))
375     {
376       [textStorage release];
378       return 0;
379     }
381   stringLength = [string length];
383   /* Force layout.  */
384   (void) [layoutManager glyphRangeForTextContainer:textContainer];
386   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
388   /* Remove the appended trailing space because otherwise it may
389      generate a wrong result for a right-to-left text.  */
390   [textStorage beginEditing];
391   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
392   [textStorage endEditing];
393   (void) [layoutManager glyphRangeForTextContainer:textContainer];
395   i = 0;
396   while (i < stringLength)
397     {
398       NSRange range;
399       NSFont *fontInTextStorage =
400         [textStorage attribute:NSFontAttributeName atIndex:i
401                      longestEffectiveRange:&range
402                        inRange:(NSMakeRange (0, stringLength))];
404       if (!(fontInTextStorage == font
405             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
406         break;
407       i = NSMaxRange (range);
408     }
409   if (i < stringLength)
410     /* Make the test `used <= glyph_len' below fail if textStorage
411        contained some fonts other than the specified one.  */
412     used = glyph_len + 1;
413   else
414     {
415       NSRange range = NSMakeRange (0, stringLength);
417       range = [layoutManager glyphRangeForCharacterRange:range
418                                     actualCharacterRange:NULL];
419       numberOfGlyphs = NSMaxRange (range);
420       used = numberOfGlyphs;
421       for (i = 0; i < numberOfGlyphs; i++)
422         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
423           used--;
424     }
426   if (0 < used && used <= glyph_len)
427     {
428       NSUInteger glyphIndex, prevGlyphIndex;
429       unsigned char bidiLevel;
430       NSUInteger *permutation;
431       NSRange compRange, range;
432       CGFloat totalAdvance;
434       glyphIndex = 0;
435       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
436         glyphIndex++;
438       /* For now we assume the direction is not changed within the
439          string.  */
440       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
441                                glyphs:NULL characterIndexes:NULL
442                     glyphInscriptions:NULL elasticBits:NULL
443                            bidiLevels:&bidiLevel];
444       if (bidiLevel & 1)
445         permutation = xmalloc (sizeof (NSUInteger) * used);
446       else
447         permutation = NULL;
449 #define RIGHT_TO_LEFT_P permutation
451       /* Fill the `comp_range' member of struct mac_glyph_layout, and
452          setup a permutation for right-to-left text.  */
453       compRange = NSMakeRange (0, 0);
454       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
455            range.length++)
456         {
457           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
458           NSUInteger characterIndex =
459             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
461           gl->string_index = characterIndex;
463           if (characterIndex >= NSMaxRange (compRange))
464             {
465               compRange.location = NSMaxRange (compRange);
466               do
467                 {
468                   NSRange characterRange =
469                     [string
470                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
472                   compRange.length =
473                     NSMaxRange (characterRange) - compRange.location;
474                   [layoutManager glyphRangeForCharacterRange:compRange
475                                         actualCharacterRange:&characterRange];
476                   characterIndex = NSMaxRange (characterRange) - 1;
477                 }
478               while (characterIndex >= NSMaxRange (compRange));
480               if (RIGHT_TO_LEFT_P)
481                 for (i = 0; i < range.length; i++)
482                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
484               range = NSMakeRange (NSMaxRange (range), 0);
485             }
487           gl->comp_range.location = compRange.location;
488           gl->comp_range.length = compRange.length;
490           while (++glyphIndex < numberOfGlyphs)
491             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
492               break;
493         }
494       if (RIGHT_TO_LEFT_P)
495         for (i = 0; i < range.length; i++)
496           permutation[range.location + i] = NSMaxRange (range) - i - 1;
498       /* Then fill the remaining members.  */
499       glyphIndex = prevGlyphIndex = 0;
500       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
501         glyphIndex++;
503       if (!RIGHT_TO_LEFT_P)
504         totalAdvance = 0;
505       else
506         {
507           NSUInteger nrects;
508           NSRect *glyphRects =
509             [layoutManager
510               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
511               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
512                      inTextContainer:textContainer rectCount:&nrects];
514           totalAdvance = NSMaxX (glyphRects[0]);
515         }
517       for (i = 0; i < used; i++)
518         {
519           struct mac_glyph_layout *gl;
520           NSPoint location;
521           NSUInteger nextGlyphIndex;
522           NSRange glyphRange;
523           NSRect *glyphRects;
524           NSUInteger nrects;
526           if (!RIGHT_TO_LEFT_P)
527             gl = glyph_layouts + i;
528           else
529             {
530               NSUInteger dest = permutation[i];
532               gl = glyph_layouts + dest;
533               if (i < dest)
534                 {
535                   CFIndex tmp = gl->string_index;
537                   gl->string_index = glyph_layouts[i].string_index;
538                   glyph_layouts[i].string_index = tmp;
539                 }
540             }
541           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
543           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
544           gl->baseline_delta = spaceLocation.y - location.y;
546           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
547                nextGlyphIndex++)
548             if (![layoutManager
549                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
550               break;
552           if (!RIGHT_TO_LEFT_P)
553             {
554               CGFloat maxX;
556               if (prevGlyphIndex == 0)
557                 glyphRange = NSMakeRange (0, nextGlyphIndex);
558               else
559                 glyphRange = NSMakeRange (glyphIndex,
560                                           nextGlyphIndex - glyphIndex);
561               glyphRects =
562                 [layoutManager
563                   rectArrayForGlyphRange:glyphRange
564                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
565                          inTextContainer:textContainer rectCount:&nrects];
566               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
567               gl->advance_delta = location.x - totalAdvance;
568               gl->advance = maxX - totalAdvance;
569               totalAdvance = maxX;
570             }
571           else
572             {
573               CGFloat minX;
575               if (nextGlyphIndex == numberOfGlyphs)
576                 glyphRange = NSMakeRange (prevGlyphIndex,
577                                           numberOfGlyphs - prevGlyphIndex);
578               else
579                 glyphRange = NSMakeRange (prevGlyphIndex,
580                                           glyphIndex + 1 - prevGlyphIndex);
581               glyphRects =
582                 [layoutManager
583                   rectArrayForGlyphRange:glyphRange
584                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
585                          inTextContainer:textContainer rectCount:&nrects];
586               minX = min (NSMinX (glyphRects[0]), totalAdvance);
587               gl->advance = totalAdvance - minX;
588               totalAdvance = minX;
589               gl->advance_delta = location.x - totalAdvance;
590             }
592           prevGlyphIndex = glyphIndex + 1;
593           glyphIndex = nextGlyphIndex;
594         }
596       if (RIGHT_TO_LEFT_P)
597         xfree (permutation);
599 #undef RIGHT_TO_LEFT_P
601       result = used;
602    }
603  [textStorage release];
605   return result;
608 static CFIndex
609 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
610                        struct mac_glyph_layout *glyph_layouts,
611                        CFIndex glyph_len)
613   return mac_font_shape_1 ([(NSFont *)font printerFont],
614                            (NSString *) string,
615                            glyph_layouts, glyph_len, YES);
618 static CGColorRef
619 get_cgcolor(unsigned long idx, struct frame *f)
621   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
622   [nsColor set];
623   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
624   NSInteger noc = [nsColor numberOfComponents];
625   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
626   CGColorRef cgColor;
628   [nsColor getComponents: components];
629   cgColor = CGColorCreate (colorSpace, components);
630   xfree (components);
631   return cgColor;
634 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
635   do {                                                                  \
636     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
637     CGContextSetFillColorWithColor (context, refcol_) ;                 \
638     CGColorRelease (refcol_);                                           \
639   } while (0)
640 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
641   do {                                                                  \
642     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
643     CGContextSetFillColorWithColor (context, refcol_);                  \
644     CGColorRelease (refcol_);                                           \
645   } while (0)
646 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
647   do {                                                                  \
648     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
649     CGContextSetStrokeColorWithColor (context, refcol_);                \
650     CGColorRelease (refcol_);                                           \
651   } while (0)
654 /* Mac font driver.  */
656 static struct
658   /* registry name */
659   const char *name;
660   /* characters to distinguish the charset from the others */
661   int uniquifier[6];
662   /* additional constraint by language */
663   CFStringRef lang;
664   /* set on demand */
665   CFCharacterSetRef cf_charset;
666   CFStringRef cf_charset_string;
667 } cf_charset_table[] =
668   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
669     { "iso8859-2", { 0x00A0, 0x010E }},
670     { "iso8859-3", { 0x00A0, 0x0108 }},
671     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
672     { "iso8859-5", { 0x00A0, 0x0401 }},
673     { "iso8859-6", { 0x00A0, 0x060C }},
674     { "iso8859-7", { 0x00A0, 0x0384 }},
675     { "iso8859-8", { 0x00A0, 0x05D0 }},
676     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
677     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
678     { "iso8859-11", { 0x00A0, 0x0E01 }},
679     { "iso8859-13", { 0x00A0, 0x201C }},
680     { "iso8859-14", { 0x00A0, 0x0174 }},
681     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
682     { "iso8859-16", { 0x00A0, 0x0218}},
683     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
684     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
685     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
686     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
687     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
688     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
689     { "cns11643.1992-3", { 0x201A9 }},
690     { "cns11643.1992-4", { 0x20057 }},
691     { "cns11643.1992-5", { 0x20000 }},
692     { "cns11643.1992-6", { 0x20003 }},
693     { "cns11643.1992-7", { 0x20055 }},
694     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
695     { "jisx0212.1990-0", { 0x4E44 }},
696     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
697     { "jisx0213.2000-2", { 0xFA49 }},
698     { "jisx0213.2004-1", { 0x20B9F }},
699     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
700     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
701     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
702     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
703     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
704     { "unicode-sip", { 0x20000 }},
705     { NULL }
706   };
708 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
709 static const struct
711   CFStringRef language;
712   CFStringRef font_names[3];
713 } macfont_language_default_font_names[] = {
714   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
715                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
716                     NULL }},
717   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
718                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
719                     NULL }},
720   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
721                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
722                          NULL }},
723   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
724                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
725                          NULL }},
726   { NULL }
728 #endif
730 static CGFloat macfont_antialias_threshold;
732 void
733 macfont_update_antialias_threshold (void)
735   int threshold;
736   Boolean valid_p;
738   threshold =
739     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
740                                      kCFPreferencesCurrentApplication,
741                                      &valid_p);
742   if (valid_p)
743     macfont_antialias_threshold = threshold;
746 static inline Lisp_Object
747 macfont_intern_prop_cfstring (CFStringRef cfstring)
749   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
751   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
754 static inline CFIndex
755 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
757   if (c < 0x10000)
758     {
759       unichars[0] = c;
761       return 1;
762     }
763   else
764     {
765       c -= 0x10000;
766       unichars[0] = (c >> 10) + 0xD800;
767       unichars[1] = (c & 0x3FF) + 0xDC00;
769       return 2;
770     }
773 static Boolean
774 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
775                                          FontSymbolicTraits *sym_traits)
777   SInt64 sint64_value;
779   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
780      OS 10.6 when the value is greater than or equal to 1 << 31.  */
781   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
782     {
783       *sym_traits = (FontSymbolicTraits) sint64_value;
785       return true;
786     }
788   return false;
791 static void
792 macfont_store_descriptor_attributes (FontDescriptorRef desc,
793                                      Lisp_Object spec_or_entity)
795   CFStringRef str;
796   CFDictionaryRef dict;
797   CFNumberRef num;
798   CGFloat floatval;
800   str = mac_font_descriptor_copy_attribute (desc,
801                                             MAC_FONT_FAMILY_NAME_ATTRIBUTE);
802   if (str)
803     {
804       ASET (spec_or_entity, FONT_FAMILY_INDEX,
805             macfont_intern_prop_cfstring (str));
806       CFRelease (str);
807     }
808   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
809   if (dict)
810     {
811       struct {
812         enum font_property_index index;
813         CFStringRef trait;
814         CGPoint points[6];
815       } numeric_traits[] =
816           {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
817             {{-0.4, 50},        /* light */
818              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
819              {0, 100},          /* normal */
820              {0.24, 140},       /* (semi-bold + normal) / 2 */
821              {0.4, 200},        /* bold */
822              {CGFLOAT_MAX, CGFLOAT_MAX}}},
823            {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
824             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
825            {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
826             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
827       int i;
829       for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); i++)
830         {
831           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
832           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
833             {
834               CGPoint *point = numeric_traits[i].points;
836               while (point->x < floatval)
837                 point++;
838               if (point == numeric_traits[i].points)
839                 point++;
840               else if (point->x == CGFLOAT_MAX)
841                 point--;
842               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
843                                            * ((point->y - (point - 1)->y)
844                                               / (point->x - (point - 1)->x)));
845               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
846                               make_number (lround (floatval)));
847             }
848         }
850       num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
851       if (num)
852         {
853           FontSymbolicTraits sym_traits;
854           int spacing;
856           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
857           spacing = (sym_traits & MAC_FONT_TRAIT_MONO_SPACE
858                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
859           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
860         }
862       CFRelease (dict);
863     }
864   num = mac_font_descriptor_copy_attribute (desc, MAC_FONT_SIZE_ATTRIBUTE);
865   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
866     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
867   else
868     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
869   if (num)
870     CFRelease (num);
873 static Lisp_Object
874 macfont_descriptor_entity (FontDescriptorRef desc, Lisp_Object extra,
875                            FontSymbolicTraits synth_sym_traits)
877   Lisp_Object entity;
878   CFDictionaryRef dict;
879   FontSymbolicTraits sym_traits = 0;
880   CFStringRef name;
882   entity = font_make_entity ();
884   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
885   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
887   macfont_store_descriptor_attributes (desc, entity);
889   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
890   if (dict)
891     {
892       CFNumberRef num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
894       if (num)
895         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
896       CFRelease (dict);
897     }
898   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
899     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
900   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
901   name = mac_font_descriptor_copy_attribute (desc, MAC_FONT_NAME_ATTRIBUTE);
902   font_put_extra (entity, QCfont_entity,
903                   make_save_ptr_int ((void *) name, sym_traits));
904   if (synth_sym_traits & MAC_FONT_TRAIT_ITALIC)
905     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
906                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
907   if (synth_sym_traits & MAC_FONT_TRAIT_BOLD)
908     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
909                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
910   if (synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
911     ASET (entity, FONT_SPACING_INDEX,
912           make_number (FONT_SPACING_SYNTHETIC_MONO));
914   return entity;
917 static CFStringRef
918 macfont_create_family_with_symbol (Lisp_Object symbol)
920   static CFArrayRef families = NULL;
921   CFStringRef result = NULL, family_name;
922   int using_cache_p = 1;
923   CFComparatorFunction family_name_comparator;
925   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
926   if (family_name == NULL)
927     return NULL;
929 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
930 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
931   if (CTFontManagerCompareFontFamilyNames != NULL)
932 #endif
933     {
934       family_name_comparator = CTFontManagerCompareFontFamilyNames;
935     }
936 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
937   else               /* CTFontManagerCompareFontFamilyNames == NULL */
938 #endif
939 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
940 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
941     {
942       family_name_comparator = mac_font_family_compare;
943     }
944 #endif
946   if ((*family_name_comparator) (family_name, CFSTR ("LastResort"), NULL)
947       == kCFCompareEqualTo)
948     result = CFSTR ("LastResort");
949   else
950     while (1)
951       {
952         CFIndex i, count;
954         if (families == NULL)
955           {
956             families = mac_font_create_available_families ();
957             using_cache_p = 0;
958             if (families == NULL)
959               break;
960           }
962         count = CFArrayGetCount (families);
963         i = CFArrayBSearchValues (families, CFRangeMake (0, count),
964                                   (const void *) family_name,
965                                   family_name_comparator, NULL);
966         if (i < count)
967           {
968             CFStringRef name = CFArrayGetValueAtIndex (families, i);
970             if ((*family_name_comparator) (name, family_name, NULL)
971                 == kCFCompareEqualTo)
972               result = CFRetain (name);
973           }
975         if (result || !using_cache_p)
976           break;
977         else
978           {
979             CFRelease (families);
980             families = NULL;
981           }
982       }
984   CFRelease (family_name);
986   return result;
989 #define WIDTH_FRAC_BITS         (4)
990 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
992 struct macfont_metrics
994   unsigned char lbearing_low, rbearing_low;
995   signed lbearing_high : 4, rbearing_high : 4;
996   unsigned char ascent_low, descent_low;
997   signed ascent_high : 4, descent_high : 4;
999   /* These two members are used for fixed-point representation of
1000      glyph width.  The `width_int' member is an integer that is
1001      closest to the width.  The `width_frac' member is the fractional
1002      adjustment representing a value in [-.5, .5], multiplied by
1003      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1004      the advance delta for centering instead of the glyph width.  */
1005   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1008 #define METRICS_VALUE(metrics, member) \
1009   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1010 #define METRICS_SET_VALUE(metrics, member, value) \
1011   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff; \
1012       (metrics)->member##_high = tmp >> 8;} while (0)
1014 enum metrics_status
1015   {
1016     METRICS_INVALID = -1,    /* metrics entry is invalid */
1017     METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1018   };
1020 #define METRICS_STATUS(metrics) \
1021   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1022 #define METRICS_SET_STATUS(metrics, status) \
1023   do {METRICS_SET_VALUE (metrics, ascent, 0); \
1024       METRICS_SET_VALUE (metrics, descent, status);} while (0)
1026 #define METRICS_NCOLS_PER_ROW   (128)
1027 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1028 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1030 static int
1031 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1032                        struct font_metrics *metrics, CGFloat *advance_delta,
1033                        int force_integral_p)
1035   struct macfont_info *macfont_info = (struct macfont_info *) font;
1036   FontRef macfont = macfont_info->macfont;
1037   int row, col;
1038   struct macfont_metrics *cache;
1039   int width;
1041   row = glyph / METRICS_NCOLS_PER_ROW;
1042   col = glyph % METRICS_NCOLS_PER_ROW;
1043   if (row >= macfont_info->metrics_nrows)
1044     {
1045       macfont_info->metrics =
1046         xrealloc (macfont_info->metrics,
1047                   sizeof (struct macfont_metrics *) * (row + 1));
1048       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1049               (sizeof (struct macfont_metrics *)
1050                * (row + 1 - macfont_info->metrics_nrows)));
1051       macfont_info->metrics_nrows = row + 1;
1052     }
1053   if (macfont_info->metrics[row] == NULL)
1054     {
1055       struct macfont_metrics *new;
1056       int i;
1058       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1059       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1060         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1061       macfont_info->metrics[row] = new;
1062     }
1063   cache = macfont_info->metrics[row] + col;
1065   if (METRICS_STATUS (cache) == METRICS_INVALID)
1066     {
1067       CGFloat fwidth;
1069       if (macfont_info->screen_font)
1070         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1071       else
1072         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1074       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1075          advance delta value.  */
1076       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1077         fwidth = (font->pixel_size - fwidth) / 2;
1078       cache->width_int = lround (fwidth);
1079       cache->width_frac = lround ((fwidth - cache->width_int)
1080                                   * WIDTH_FRAC_SCALE);
1081       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1082     }
1083   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1084     width = font->pixel_size;
1085   else
1086     width = cache->width_int;
1088   if (metrics)
1089     {
1090       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1091         {
1092           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1094           if (macfont_info->synthetic_italic_p)
1095             {
1096               /* We assume the members a, b, c, and d in
1097                  synthetic_italic_atfm are non-negative.  */
1098               bounds.origin =
1099                 CGPointApplyAffineTransform (bounds.origin,
1100                                              synthetic_italic_atfm);
1101               bounds.size =
1102                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1103             }
1104           if (macfont_info->synthetic_bold_p)
1105             {
1106               CGFloat d =
1107                 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1109               bounds = CGRectInset (bounds, d, d);
1110             }
1111           switch (macfont_info->spacing)
1112             {
1113             case MACFONT_SPACING_PROPORTIONAL:
1114               bounds.origin.x += - (cache->width_frac
1115                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1116               break;
1117             case MACFONT_SPACING_MONO:
1118               break;
1119             case MACFONT_SPACING_SYNTHETIC_MONO:
1120               bounds.origin.x += (cache->width_int
1121                                   + (cache->width_frac
1122                                      / (CGFloat) WIDTH_FRAC_SCALE));
1123               break;
1124             }
1125           if (bounds.size.width > 0)
1126             {
1127               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1128               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1129                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1130             }
1131           bounds = CGRectIntegral (bounds);
1132           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1133           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1134           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1135           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1136         }
1137       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1138       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1139       metrics->width = width;
1140       metrics->ascent = METRICS_VALUE (cache, ascent);
1141       metrics->descent = METRICS_VALUE (cache, descent);
1142     }
1144   if (advance_delta)
1145     {
1146       switch (macfont_info->spacing)
1147         {
1148         case MACFONT_SPACING_PROPORTIONAL:
1149           *advance_delta = (force_integral_p ? 0
1150                             : - (cache->width_frac
1151                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1152           break;
1153         case MACFONT_SPACING_MONO:
1154           *advance_delta = 0;
1155           break;
1156         case MACFONT_SPACING_SYNTHETIC_MONO:
1157           *advance_delta = (force_integral_p ? cache->width_int
1158                             : (cache->width_int
1159                                + (cache->width_frac
1160                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1161           break;
1162         }
1163     }
1165   return width;
1168 static CFMutableDictionaryRef macfont_cache_dictionary;
1170 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1171    equal to the number of rows that are invalid as BMP (i.e., from
1172    U+D800 to U+DFFF).  */
1173 #define ROW_PERM_OFFSET (8)
1175 /* The number of glyphs that can be stored in a value for a single
1176    entry of CFDictionary.  */
1177 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1179 struct macfont_cache
1181   int reference_count;
1182   CFCharacterSetRef cf_charset;
1183   struct {
1184     /* The cached glyph for a BMP character c is stored in
1185        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1186        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1187     unsigned char row_nkeys_or_perm[256];
1188     CGGlyph **matrix;
1190     /* Number of rows for which the BMP cache is allocated so far.
1191        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1192     int nrows;
1194     /* The cached glyph for a character c is stored as the (c %
1195        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1196        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1197        not stored here if row_nkeys_or_perm[c / 256] >=
1198        ROW_PERM_OFFSET.  */
1199     CFMutableDictionaryRef dictionary;
1200   } glyph;
1202   struct {
1203     /* UVS (Unicode Variation Sequence) subtable data, which is of
1204        type CFDataRef if available.  NULL means it is not initialized
1205        yet.  kCFNull means the subtable is not found and there is no
1206        suitable fallback table for this font.  */
1207     CFTypeRef table;
1209     /* Character collection specifying the destination of the mapping
1210        provided by `table' above.  If `table' is obtained from the UVS
1211        subtable in the font cmap table, then the value of this member
1212        should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING.  */
1213     CharacterCollection collection;
1214   } uvs;
1217 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1218 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1219 static void macfont_release_cache (struct macfont_cache *);
1220 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1221 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1222 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1223 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1224                                           CharacterCollection, CGFontIndex);
1225 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1227 static struct macfont_cache *
1228 macfont_lookup_cache (CFStringRef key)
1230   struct macfont_cache *cache;
1232   if (macfont_cache_dictionary == NULL)
1233     {
1234       macfont_cache_dictionary =
1235         CFDictionaryCreateMutable (NULL, 0,
1236                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1237       cache = NULL;
1238     }
1239   else
1240     cache = ((struct macfont_cache *)
1241              CFDictionaryGetValue (macfont_cache_dictionary, key));
1243   if (cache == NULL)
1244     {
1245       FontRef macfont = mac_font_create_with_name (key, 0);
1247       if (macfont)
1248         {
1249           cache = xzalloc (sizeof (struct macfont_cache));
1250           /* Treat the LastResort font as if it contained glyphs for
1251              all characters.  This may look too rough, but neither
1252              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1253              for this font is correct for non-BMP characters on Mac OS
1254              X 10.5, anyway.  */
1255           if (CFStringCompare (key, CFSTR ("LastResort"), 0)
1256               == kCFCompareEqualTo)
1257             {
1258               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1260               cache->cf_charset =
1261                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1262             }
1263           if (cache->cf_charset == NULL)
1264             cache->cf_charset = mac_font_copy_character_set (macfont);
1265           CFDictionaryAddValue (macfont_cache_dictionary, key,
1266                                 (const void *) cache);
1267           CFRelease (macfont);
1268         }
1269     }
1271   return cache;
1274 static struct macfont_cache *
1275 macfont_retain_cache (struct macfont_cache *cache)
1277   cache->reference_count++;
1279   return cache;
1282 static void
1283 macfont_release_cache (struct macfont_cache *cache)
1285   if (--cache->reference_count == 0)
1286     {
1287       int i;
1289       for (i = 0; i < cache->glyph.nrows; i++)
1290         xfree (cache->glyph.matrix[i]);
1291       xfree (cache->glyph.matrix);
1292       if (cache->glyph.dictionary)
1293         CFRelease (cache->glyph.dictionary);
1294       memset (&cache->glyph, 0, sizeof (cache->glyph));
1295       if (cache->uvs.table)
1296         CFRelease (cache->uvs.table);
1297       memset (&cache->uvs, 0, sizeof (cache->uvs));
1298     }
1301 static CFCharacterSetRef
1302 macfont_get_cf_charset (struct font *font)
1304   struct macfont_info *macfont_info = (struct macfont_info *) font;
1306   return macfont_info->cache->cf_charset;
1309 static CFCharacterSetRef
1310 macfont_get_cf_charset_for_name (CFStringRef name)
1312   struct macfont_cache *cache = macfont_lookup_cache (name);
1314   return cache->cf_charset;
1317 static CGGlyph
1318 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1320   struct macfont_info *macfont_info = (struct macfont_info *) font;
1321   FontRef macfont = macfont_info->macfont;
1322   struct macfont_cache *cache = macfont_info->cache;
1324   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1325     {
1326       int row = c / 256;
1327       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1329       if (nkeys_or_perm < ROW_PERM_OFFSET)
1330         {
1331           UniChar unichars[256], ch;
1332           CGGlyph *glyphs;
1333           int i, len;
1334           int nrows;
1335 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1336           dispatch_queue_t queue;
1337           dispatch_group_t group = NULL;
1338 #else
1339           int nkeys;
1340 #endif
1342           if (row != 0)
1343             {
1344               CFMutableDictionaryRef dictionary;
1345               uintptr_t key, value;
1346               int nshifts;
1347               CGGlyph glyph;
1349               if (cache->glyph.dictionary == NULL)
1350                 cache->glyph.dictionary =
1351                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1352               dictionary = cache->glyph.dictionary;
1353               key = c / NGLYPHS_IN_VALUE;
1354               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1355               value = ((uintptr_t)
1356                        CFDictionaryGetValue (dictionary, (const void *) key));
1357               glyph = (value >> nshifts);
1358               if (glyph)
1359                 return glyph;
1361               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1362                 {
1363                   ch = c;
1364                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1365                                                            &glyph, 1)
1366                       || glyph == 0)
1367                     glyph = kCGFontIndexInvalid;
1369                   if (value == 0)
1370                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1371                   value |= ((uintptr_t) glyph << nshifts);
1372                   CFDictionarySetValue (dictionary, (const void *) key,
1373                                         (const void *) value);
1375                   return glyph;
1376                 }
1378 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1379               queue =
1380                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1381               group = dispatch_group_create ();
1382               dispatch_group_async (group, queue, ^{
1383                   int nkeys;
1384                   uintptr_t key;
1385 #endif
1386                   nkeys = nkeys_or_perm;
1387                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1388                     if (CFDictionaryContainsKey (dictionary,
1389                                                  (const void *) key))
1390                       {
1391                         CFDictionaryRemoveValue (dictionary,
1392                                                  (const void *) key);
1393                         if (--nkeys == 0)
1394                           break;
1395                       }
1396 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1397                 });
1398 #endif
1399             }
1401           len = 0;
1402           for (i = 0; i < 256; i++)
1403             {
1404               ch = row * 256 + i;
1405               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1406                 unichars[len++] = ch;
1407             }
1409           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1410           if (len > 0)
1411             {
1412               mac_font_get_glyphs_for_characters (macfont, unichars,
1413                                                   glyphs, len);
1414               while (i > len)
1415                 {
1416                   int next = unichars[len - 1] % 256;
1418                   while (--i > next)
1419                     glyphs[i] = kCGFontIndexInvalid;
1421                   len--;
1422                   glyphs[i] = glyphs[len];
1423                   if (len == 0)
1424                     break;
1425                 }
1426             }
1427           if (i > len)
1428             while (i-- > 0)
1429               glyphs[i] = kCGFontIndexInvalid;
1431           nrows = cache->glyph.nrows;
1432           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1433           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1434           nrows++;
1435           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1436                                           sizeof (CGGlyph *) * nrows);
1437           cache->glyph.matrix[nrows - 1] = glyphs;
1438           cache->glyph.nrows = nrows;
1440 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1441           if (group)
1442             {
1443               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1444               dispatch_release (group);
1445             }
1446 #endif
1447         }
1449       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1450     }
1451   else
1452     {
1453       uintptr_t key, value;
1454       int nshifts;
1455       CGGlyph glyph;
1457       if (cache->glyph.dictionary == NULL)
1458         cache->glyph.dictionary =
1459           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1460       key = c / NGLYPHS_IN_VALUE;
1461       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1462       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1463                                                 (const void *) key);
1464       glyph = (value >> nshifts);
1465       if (glyph == 0)
1466         {
1467           UniChar unichars[2];
1468           CGGlyph glyphs[2];
1469           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1471           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1472                                                   count))
1473             glyph = glyphs[0];
1474           if (glyph == 0)
1475             glyph = kCGFontIndexInvalid;
1477           value |= ((uintptr_t) glyph << nshifts);
1478           CFDictionarySetValue (cache->glyph.dictionary,
1479                                 (const void *) key, (const void *) value);
1480         }
1482       return glyph;
1483     }
1486 static CGGlyph
1487 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1488                            CGFontIndex cid)
1490   struct macfont_info *macfont_info = (struct macfont_info *) font;
1491   FontRef macfont = macfont_info->macfont;
1493   /* Cache it? */
1494   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1497 static CFDataRef
1498 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1500   struct macfont_info *macfont_info = (struct macfont_info *) font;
1501   FontRef macfont = macfont_info->macfont;
1502   struct macfont_cache *cache = macfont_info->cache;
1503   CFDataRef result = NULL;
1505   if (cache->uvs.table == NULL)
1506     {
1507       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1508       CharacterCollection uvs_collection =
1509         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1511       if (uvs_table == NULL
1512           && mac_font_get_glyph_for_cid (macfont,
1513                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1514                                          6480) != kCGFontIndexInvalid)
1515         {
1516           /* If the glyph for U+4E55 is accessible via its CID 6480,
1517              then we use the Adobe-Japan1 UVS table, which maps a
1518              variation sequence to a CID, as a fallback.  */
1519           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1521           if (mac_uvs_table_adobe_japan1 == NULL)
1522             mac_uvs_table_adobe_japan1 =
1523               CFDataCreateWithBytesNoCopy (NULL,
1524                                            mac_uvs_table_adobe_japan1_bytes,
1525                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1526                                            kCFAllocatorNull);
1527           if (mac_uvs_table_adobe_japan1)
1528             {
1529               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1530               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1531             }
1532         }
1533       if (uvs_table == NULL)
1534         cache->uvs.table = kCFNull;
1535       else
1536         cache->uvs.table = uvs_table;
1537       cache->uvs.collection = uvs_collection;
1538     }
1540   if (cache->uvs.table != kCFNull)
1541     {
1542       result = cache->uvs.table;
1543       *collection = cache->uvs.collection;
1544     }
1546   return result;
1549 static Lisp_Object macfont_get_cache (struct frame *);
1550 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1551 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1552 static Lisp_Object macfont_list_family (struct frame *);
1553 static void macfont_free_entity (Lisp_Object);
1554 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1555 static void macfont_close (struct font *);
1556 static int macfont_has_char (Lisp_Object, int);
1557 static unsigned macfont_encode_char (struct font *, int);
1558 static int macfont_text_extents (struct font *, unsigned int *, int,
1559                                  struct font_metrics *);
1560 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1561 static Lisp_Object macfont_shape (Lisp_Object);
1562 static int macfont_variation_glyphs (struct font *, int c,
1563                                      unsigned variations[256]);
1564 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1566 static struct font_driver macfont_driver =
1567   {
1568     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1569     0,                          /* case insensitive */
1570     macfont_get_cache,
1571     macfont_list,
1572     macfont_match,
1573     macfont_list_family,
1574     macfont_free_entity,
1575     macfont_open,
1576     macfont_close,
1577     NULL,                       /* prepare_face */
1578     NULL,                       /* done_face */
1579     macfont_has_char,
1580     macfont_encode_char,
1581     macfont_text_extents,
1582     macfont_draw,
1583     NULL,                       /* get_bitmap */
1584     NULL,                       /* free_bitmap */
1585     NULL,                       /* get_outline */
1586     NULL,                       /* free_outline */
1587     NULL,                       /* anchor_point */
1588     NULL,                       /* otf_capability */
1589     NULL,                       /* otf_drive */
1590     NULL,                       /* start_for_frame */
1591     NULL,                       /* end_for_frame */
1592     macfont_shape,
1593     NULL,                       /* check */
1594     macfont_variation_glyphs,
1595     macfont_filter_properties,
1596   };
1598 static Lisp_Object
1599 macfont_get_cache (struct frame * f)
1601   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1603   return (dpyinfo->name_list_element);
1606 static int
1607 macfont_get_charset (Lisp_Object registry)
1609   char *str = SSDATA (SYMBOL_NAME (registry));
1610   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1611   Lisp_Object regexp;
1612   int i, j;
1614   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1615     {
1616       if (str[i] == '.')
1617         re[j++] = '\\';
1618       else if (str[i] == '*')
1619         re[j++] = '.';
1620       re[j] = str[i];
1621       if (re[j] == '?')
1622         re[j] = '.';
1623     }
1624   re[j] = '\0';
1625   regexp = make_unibyte_string (re, j);
1626   for (i = 0; cf_charset_table[i].name; i++)
1627     if (fast_c_string_match_ignore_case
1628         (regexp, cf_charset_table[i].name,
1629          strlen (cf_charset_table[i].name)) >= 0)
1630       break;
1631   if (! cf_charset_table[i].name)
1632     return -1;
1633   if (! cf_charset_table[i].cf_charset)
1634     {
1635       int *uniquifier = cf_charset_table[i].uniquifier;
1636       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1637       CFIndex count = 0;
1638       CFStringRef string;
1639       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1641       if (! charset)
1642         return -1;
1643       for (j = 0; uniquifier[j]; j++)
1644         {
1645           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1646                                                         unichars + count);
1647           CFCharacterSetAddCharactersInRange (charset,
1648                                               CFRangeMake (uniquifier[j], 1));
1649         }
1651       string = CFStringCreateWithCharacters (NULL, unichars, count);
1652       if (! string)
1653         {
1654           CFRelease (charset);
1655           return -1;
1656         }
1657       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1658                                                                  charset);
1659       CFRelease (charset);
1660       /* CFCharacterSetCreateWithCharactersInString does not handle
1661          surrogate pairs properly as of Mac OS X 10.5.  */
1662      cf_charset_table[i].cf_charset_string = string;
1663     }
1664   return i;
1667 struct OpenTypeSpec
1669   Lisp_Object script;
1670   unsigned int script_tag, langsys_tag;
1671   int nfeatures[2];
1672   unsigned int *features[2];
1675 #define OTF_SYM_TAG(SYM, TAG)                                   \
1676   do {                                                          \
1677     unsigned char *p = SDATA (SYMBOL_NAME (SYM));               \
1678     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1679   } while (0)
1681 #define OTF_TAG_STR(TAG, P)                     \
1682   do {                                          \
1683     (P)[0] = (char) (TAG >> 24);                \
1684     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1685     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1686     (P)[3] = (char) (TAG & 0xFF);               \
1687     (P)[4] = '\0';                              \
1688   } while (0)
1690 static struct OpenTypeSpec *
1691 macfont_get_open_type_spec (Lisp_Object otf_spec)
1693   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1694   Lisp_Object val;
1695   int i, j;
1696   bool negative;
1698   if (! spec)
1699     return NULL;
1700   spec->script = XCAR (otf_spec);
1701   if (! NILP (spec->script))
1702     {
1703       OTF_SYM_TAG (spec->script, spec->script_tag);
1704       val = assq_no_quit (spec->script, Votf_script_alist);
1705       if (CONSP (val) && SYMBOLP (XCDR (val)))
1706         spec->script = XCDR (val);
1707       else
1708         spec->script = Qnil;
1709     }
1710   else
1711     spec->script_tag = 0x44464C54;      /* "DFLT" */
1712   otf_spec = XCDR (otf_spec);
1713   spec->langsys_tag = 0;
1714   if (! NILP (otf_spec))
1715     {
1716       val = XCAR (otf_spec);
1717       if (! NILP (val))
1718         OTF_SYM_TAG (val, spec->langsys_tag);
1719       otf_spec = XCDR (otf_spec);
1720     }
1721   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1722   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1723     {
1724       Lisp_Object len;
1726       val = XCAR (otf_spec);
1727       if (NILP (val))
1728         continue;
1729       len = Flength (val);
1730       spec->features[i] =
1731         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1732          ? 0
1733          : malloc (XINT (len) * sizeof *spec->features[i]));
1734       if (! spec->features[i])
1735         {
1736           if (i > 0 && spec->features[0])
1737             free (spec->features[0]);
1738           free (spec);
1739           return NULL;
1740         }
1741       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1742         {
1743           if (NILP (XCAR (val)))
1744             negative = 1;
1745           else
1746             {
1747               unsigned int tag;
1749               OTF_SYM_TAG (XCAR (val), tag);
1750               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1751             }
1752         }
1753       spec->nfeatures[i] = j;
1754     }
1755   return spec;
1758 static CFMutableDictionaryRef
1759 macfont_create_attributes_with_spec (Lisp_Object spec)
1761   Lisp_Object tmp, extra;
1762   CFMutableArrayRef langarray = NULL;
1763   CFCharacterSetRef charset = NULL;
1764   CFStringRef charset_string = NULL;
1765   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1766   Lisp_Object script = Qnil;
1767   Lisp_Object registry;
1768   int cf_charset_idx, i;
1769   struct OpenTypeSpec *otspec = NULL;
1770   struct {
1771     enum font_property_index index;
1772     CFStringRef trait;
1773     CGPoint points[6];
1774   } numeric_traits[] =
1775       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1776         {{-0.4, 50},            /* light */
1777          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1778          {0, 100},              /* normal */
1779          {0.24, 140},           /* (semi-bold + normal) / 2 */
1780          {0.4, 200},            /* bold */
1781          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1782        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1783         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1784        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1785         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1787   registry = AREF (spec, FONT_REGISTRY_INDEX);
1788   if (NILP (registry)
1789       || EQ (registry, Qascii_0)
1790       || EQ (registry, Qiso10646_1)
1791       || EQ (registry, Qunicode_bmp))
1792     cf_charset_idx = -1;
1793   else
1794     {
1795       CFStringRef lang;
1797       cf_charset_idx = macfont_get_charset (registry);
1798       if (cf_charset_idx < 0)
1799         goto err;
1800       charset = cf_charset_table[cf_charset_idx].cf_charset;
1801       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1802       lang = cf_charset_table[cf_charset_idx].lang;
1803       if (lang)
1804         {
1805           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1806           if (! langarray)
1807             goto err;
1808           CFArrayAppendValue (langarray, lang);
1809         }
1810     }
1812   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1813        CONSP (extra); extra = XCDR (extra))
1814     {
1815       Lisp_Object key, val;
1817       tmp = XCAR (extra);
1818       key = XCAR (tmp), val = XCDR (tmp);
1819       if (EQ (key, QClang))
1820         {
1821           if (! langarray)
1822             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1823           if (! langarray)
1824             goto err;
1825           if (SYMBOLP (val))
1826             val = list1 (val);
1827           for (; CONSP (val); val = XCDR (val))
1828             if (SYMBOLP (XCAR (val)))
1829               {
1830                 CFStringRef lang =
1831                   cfstring_create_with_string_noencode (SYMBOL_NAME
1832                                                         (XCAR (val)));
1834                 if (lang == NULL)
1835                   goto err;
1836                 CFArrayAppendValue (langarray, lang);
1837                 CFRelease (lang);
1838               }
1839         }
1840       else if (EQ (key, QCotf))
1841         {
1842           otspec = macfont_get_open_type_spec (val);
1843           if (! otspec)
1844             goto err;
1845           script = otspec->script;
1846         }
1847       else if (EQ (key, QCscript))
1848         script = val;
1849     }
1851   if (! NILP (script) && ! charset)
1852     {
1853       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1855       if (CONSP (chars) && CONSP (CDR (chars)))
1856         {
1857           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1858           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1860           if (! string || !cs)
1861             {
1862               if (string)
1863                 CFRelease (string);
1864               else if (cs)
1865                 CFRelease (cs);
1866               goto err;
1867             }
1868           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1869             if (CHARACTERP (XCAR (chars)))
1870               {
1871                 UniChar unichars[2];
1872                 CFIndex count =
1873                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1874                                                        unichars);
1875                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1877                 CFStringAppendCharacters (string, unichars, count);
1878                 CFCharacterSetAddCharactersInRange (cs, range);
1879               }
1880           charset = cs;
1881           /* CFCharacterSetCreateWithCharactersInString does not
1882              handle surrogate pairs properly as of Mac OS X 10.5.  */
1883           charset_string = string;
1884         }
1885     }
1887   attributes = CFDictionaryCreateMutable (NULL, 0,
1888                                           &kCFTypeDictionaryKeyCallBacks,
1889                                           &kCFTypeDictionaryValueCallBacks);
1890   if (! attributes)
1891     goto err;
1893   tmp = AREF (spec, FONT_FAMILY_INDEX);
1894   if (SYMBOLP (tmp) && ! NILP (tmp))
1895     {
1896       CFStringRef family = macfont_create_family_with_symbol (tmp);
1898       if (! family)
1899         goto err;
1900       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1901                             family);
1902       CFRelease (family);
1903     }
1905   traits = CFDictionaryCreateMutable (NULL, 4,
1906                                       &kCFTypeDictionaryKeyCallBacks,
1907                                       &kCFTypeDictionaryValueCallBacks);
1908   if (! traits)
1909     goto err;
1911   for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); i++)
1912     {
1913       tmp = AREF (spec, numeric_traits[i].index);
1914       if (INTEGERP (tmp))
1915         {
1916           CGPoint *point = numeric_traits[i].points;
1917           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1918           CFNumberRef num;
1920           while (point->y < floatval)
1921             point++;
1922           if (point == numeric_traits[i].points)
1923             point++;
1924           else if (point->y == CGFLOAT_MAX)
1925             point--;
1926           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1927                                        * ((point->x - (point - 1)->x)
1928                                           / (point->y - (point - 1)->y)));
1929           if (floatval > 1.0)
1930             floatval = 1.0;
1931           else if (floatval < -1.0)
1932             floatval = -1.0;
1933           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1934           if (! num)
1935             goto err;
1936           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1937           CFRelease (num);
1938         }
1939     }
1940   if (CFDictionaryGetCount (traits))
1941     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1943   if (charset)
1944     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1945                           charset);
1946   if (charset_string)
1947     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1948                           charset_string);
1949   if (langarray)
1950     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1952   goto finish;
1954  err:
1955   if (attributes)
1956     {
1957       CFRelease (attributes);
1958       attributes = NULL;
1959     }
1961  finish:
1962   if (langarray) CFRelease (langarray);
1963   if (charset && cf_charset_idx < 0) CFRelease (charset);
1964   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1965   if (traits) CFRelease (traits);
1966   if (otspec)
1967     {
1968       if (otspec->nfeatures[0] > 0)
1969         free (otspec->features[0]);
1970       if (otspec->nfeatures[1] > 0)
1971         free (otspec->features[1]);
1972       free (otspec);
1973     }
1975   return attributes;
1978 static Boolean
1979 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1980                                           CFCharacterSetRef charset,
1981                                           Lisp_Object chars,
1982                                           CFArrayRef languages)
1984   Boolean result = true;
1986   if (charset || VECTORP (chars))
1987     {
1988       CFCharacterSetRef desc_charset =
1989         mac_font_descriptor_copy_attribute (desc,
1990                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1992       if (desc_charset == NULL)
1993         result = false;
1994       else
1995         {
1996           if (charset)
1997             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1998           else                  /* VECTORP (chars) */
1999             {
2000               ptrdiff_t j;
2002               for (j = 0; j < ASIZE (chars); j++)
2003                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2004                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2005                                                             XFASTINT (AREF (chars, j))))
2006                   break;
2007               if (j == ASIZE (chars))
2008                 result = false;
2009             }
2010           CFRelease (desc_charset);
2011         }
2012     }
2013   if (result && languages)
2014     result = mac_font_descriptor_supports_languages (desc, languages);
2016   return result;
2019 static CFIndex
2020 macfont_closest_traits_index (CFArrayRef traits_array,
2021                               FontSymbolicTraits target)
2023   CFIndex i, result = -1, count = CFArrayGetCount (traits_array);
2024   int min_distance = (1 << 3);
2026   for (i = 0; i < count; i++)
2027     {
2028       FontSymbolicTraits traits, diff;
2029       int distance = 0;
2031       traits = ((FontSymbolicTraits) (uintptr_t)
2032                 CFArrayGetValueAtIndex (traits_array, i));
2033       diff = (target ^ traits);
2034       /* We prefer synthetic bold of italic to synthetic italic of
2035          bold when both bold and italic are available but bold-italic
2036          is not available.  */
2037       if (diff & MAC_FONT_TRAIT_BOLD)
2038         distance |= (1 << 0);
2039       if (diff & MAC_FONT_TRAIT_ITALIC)
2040         distance |= (1 << 1);
2041       if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2042         distance |= (1 << 2);
2043       if (distance < min_distance)
2044         {
2045           min_distance = distance;
2046           result = i;
2047         }
2048     }
2050   return result;
2053 static Lisp_Object
2054 macfont_list (struct frame *f, Lisp_Object spec)
2056   Lisp_Object val = Qnil, family, extra;
2057   int i, n;
2058   CFStringRef family_name = NULL;
2059   CFMutableDictionaryRef attributes = NULL, traits;
2060   Lisp_Object chars = Qnil;
2061   int spacing = -1;
2062   FontSymbolicTraits synth_sym_traits = 0;
2063   CFArrayRef families;
2064   CFIndex families_count;
2065   CFCharacterSetRef charset = NULL;
2066   CFArrayRef languages = NULL;
2068   block_input ();
2070   family = AREF (spec, FONT_FAMILY_INDEX);
2071   if (! NILP (family))
2072     {
2073       family_name = macfont_create_family_with_symbol (family);
2074       if (family_name == NULL)
2075         goto finish;
2076     }
2078   attributes = macfont_create_attributes_with_spec (spec);
2079   if (! attributes)
2080     goto finish;
2082   languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2084   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2085     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2087   traits = ((CFMutableDictionaryRef)
2088             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2090   n = FONT_SLANT_NUMERIC (spec);
2091   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2092     {
2093       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2094       if (traits)
2095         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2096     }
2098   n = FONT_WEIGHT_NUMERIC (spec);
2099   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2100     {
2101       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2102       if (traits)
2103         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2104     }
2106   if (languages
2107       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2108     {
2109       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2111       if (CFStringHasPrefix (language, CFSTR ("ja"))
2112           || CFStringHasPrefix (language, CFSTR ("ko"))
2113           || CFStringHasPrefix (language, CFSTR ("zh")))
2114         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2115     }
2117   /* Create array of families.  */
2118   if (family_name)
2119     families = CFArrayCreate (NULL, (const void **) &family_name,
2120                               1, &kCFTypeArrayCallBacks);
2121   else
2122     {
2123       CFStringRef pref_family;
2124       CFIndex families_count, pref_family_index = -1;
2126       families = mac_font_create_available_families ();
2127       if (families == NULL)
2128         goto err;
2130       families_count = CFArrayGetCount (families);
2132       /* Move preferred family to the front if exists.  */
2133       pref_family =
2134         mac_font_create_preferred_family_for_attributes (attributes);
2135       if (pref_family)
2136         {
2137           pref_family_index =
2138             CFArrayGetFirstIndexOfValue (families,
2139                                          CFRangeMake (0, families_count),
2140                                          pref_family);
2141           CFRelease (pref_family);
2142         }
2143       if (pref_family_index > 0)
2144         {
2145           CFMutableArrayRef mutable_families =
2146             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2148           if (mutable_families)
2149             {
2150               CFArrayAppendValue (mutable_families,
2151                                   CFArrayGetValueAtIndex (families,
2152                                                           pref_family_index));
2153               CFArrayAppendArray (mutable_families, families,
2154                                   CFRangeMake (0, pref_family_index));
2155               if (pref_family_index + 1 < families_count)
2156                 CFArrayAppendArray (mutable_families, families,
2157                                     CFRangeMake (pref_family_index + 1,
2158                                                  families_count
2159                                                  - (pref_family_index + 1)));
2160               CFRelease (families);
2161               families = mutable_families;
2162             }
2163         }
2164     }
2166   charset = CFDictionaryGetValue (attributes,
2167                                   MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2168   if (charset)
2169     {
2170       CFRetain (charset);
2171       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2172     }
2173   else
2174     {
2175       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2176       if (! NILP (val))
2177         {
2178           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2179           if (CONSP (val) && VECTORP (XCDR (val)))
2180             chars = XCDR (val);
2181         }
2182       val = Qnil;
2183     }
2185   if (languages)
2186     {
2187       CFRetain (languages);
2188       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2189     }
2191   val = Qnil;
2192   extra = AREF (spec, FONT_EXTRA_INDEX);
2193   families_count = CFArrayGetCount (families);
2194   for (i = 0; i < families_count; i++)
2195     {
2196       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2197       FontDescriptorRef pat_desc;
2198       CFArrayRef descs;
2199       CFIndex descs_count;
2200       CFMutableArrayRef filtered_descs, traits_array;
2201       Lisp_Object entity;
2202       int j;
2204       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2205                             family_name);
2206       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2207       if (! pat_desc)
2208         goto err;
2210       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2211          10.7 returns NULL if pat_desc represents the LastResort font.
2212          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2213          trailing "s") for such a font.  */
2214       if (CFStringCompare (family_name, CFSTR ("LastResort"), 0)
2215           != kCFCompareEqualTo)
2216         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2217                                                                       NULL);
2218       else
2219         {
2220           FontDescriptorRef lr_desc =
2221             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2222                                                                  NULL);
2223           if (lr_desc)
2224             {
2225               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2226                                      &kCFTypeArrayCallBacks);
2227               CFRelease (lr_desc);
2228             }
2229           else
2230             descs = NULL;
2231         }
2232       CFRelease (pat_desc);
2233       if (! descs)
2234         goto err;
2236       descs_count = CFArrayGetCount (descs);
2237       if (descs_count == 0
2238           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2239                                                         charset, chars,
2240                                                         languages))
2241         {
2242           CFRelease (descs);
2243           continue;
2244         }
2246       filtered_descs =
2247         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2248       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2249       for (j = 0; j < descs_count; j++)
2250         {
2251           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2252           CFDictionaryRef dict;
2253           CFNumberRef num;
2254           FontSymbolicTraits sym_traits;
2256           dict = mac_font_descriptor_copy_attribute (desc,
2257                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2258           if (dict == NULL)
2259             continue;
2261           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2262           CFRelease (dict);
2263           if (num == NULL
2264               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2265             continue;
2267           if (spacing >= 0
2268               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2269               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2270                   != (spacing >= FONT_SPACING_MONO)))
2271             continue;
2273           /* Don't use a color bitmap font unless its family is
2274              explicitly specified.  */
2275           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2276             continue;
2278           if (j > 0
2279               && !macfont_supports_charset_and_languages_p (desc, charset,
2280                                                             chars, languages))
2281             continue;
2283           CFArrayAppendValue (filtered_descs, desc);
2284           CFArrayAppendValue (traits_array,
2285                               (const void *) (uintptr_t) sym_traits);
2286         }
2288       CFRelease (descs);
2289       descs = filtered_descs;
2290       descs_count = CFArrayGetCount (descs);
2292       for (j = 0; j < descs_count; j++)
2293         {
2294           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2295           FontSymbolicTraits sym_traits =
2296             ((FontSymbolicTraits) (uintptr_t)
2297              CFArrayGetValueAtIndex (traits_array, j));
2298           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2300           mask_min = ((synth_sym_traits ^ sym_traits)
2301                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2302           if (FONT_SLANT_NUMERIC (spec) < 0)
2303             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2304           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2305             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2307           mask_max = (synth_sym_traits & ~sym_traits);
2308           /* Synthetic bold does not work for bitmap-only fonts on Mac
2309              OS X 10.6.  */
2310           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2311             {
2312               CFNumberRef format =
2313                 mac_font_descriptor_copy_attribute (desc,
2314                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2316               if (format)
2317                 {
2318                   uint32_t format_val;
2320                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2321                                         &format_val)
2322                       && format_val == MAC_FONT_FORMAT_BITMAP)
2323                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2324                 }
2325             }
2326           if (spacing >= 0)
2327             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2329           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2330                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2331                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2332             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2333                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2334                  bmask += MAC_FONT_TRAIT_BOLD)
2335               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2336                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2337                    imask += MAC_FONT_TRAIT_ITALIC)
2338                 {
2339                   FontSymbolicTraits synth = (imask | bmask | mmask);
2341                   if (synth == 0
2342                       || j == macfont_closest_traits_index (traits_array,
2343                                                             (sym_traits | synth)))
2344                     {
2345                       entity = macfont_descriptor_entity (desc, extra, synth);
2346                       if (! NILP (entity))
2347                         val = Fcons (entity, val);
2348                     }
2349                 }
2350         }
2352       CFRelease (traits_array);
2353       CFRelease (descs);
2354     }
2356   CFRelease (families);
2357   val = Fnreverse (val);
2358   goto finish;
2359  err:
2360   val = Qnil;
2362  finish:
2363   FONT_ADD_LOG ("macfont-list", spec, val);
2364   if (charset) CFRelease (charset);
2365   if (languages) CFRelease (languages);
2366   if (attributes) CFRelease (attributes);
2367   if (family_name) CFRelease (family_name);
2369   unblock_input ();
2371   return val;
2374 static Lisp_Object
2375 macfont_match (struct frame * frame, Lisp_Object spec)
2377   Lisp_Object entity = Qnil;
2378   CFMutableDictionaryRef attributes;
2379   FontDescriptorRef pat_desc = NULL, desc = NULL;
2381   block_input ();
2383   attributes = macfont_create_attributes_with_spec (spec);
2384   if (attributes)
2385     {
2386       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2387       CFRelease (attributes);
2388     }
2389   if (pat_desc)
2390     {
2391       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2392                                                                   NULL);
2393       CFRelease (pat_desc);
2394     }
2395   if (desc)
2396     {
2397       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2398                                           0);
2399       CFRelease (desc);
2400     }
2401   unblock_input ();
2403   FONT_ADD_LOG ("macfont-match", spec, entity);
2404   return entity;
2407 static Lisp_Object
2408 macfont_list_family (struct frame *frame)
2410   Lisp_Object list = Qnil;
2411   CFArrayRef families;
2413   block_input ();
2415   families = mac_font_create_available_families ();
2416   if (families)
2417     {
2418       CFIndex i, count = CFArrayGetCount (families);
2420       for (i = 0; i < count; i++)
2421         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2422       CFRelease (families);
2423     }
2425   unblock_input ();
2427   return list;
2430 static void
2431 macfont_free_entity (Lisp_Object entity)
2433   Lisp_Object val = assq_no_quit (QCfont_entity,
2434                                   AREF (entity, FONT_EXTRA_INDEX));
2435   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2437   block_input ();
2438   CFRelease (name);
2439   unblock_input ();
2442 static Lisp_Object
2443 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2445   Lisp_Object val, font_object;
2446   CFStringRef font_name;
2447   struct macfont_info *macfont_info = NULL;
2448   struct font *font;
2449   int size;
2450   FontRef macfont;
2451   FontSymbolicTraits sym_traits;
2452   char name[256];
2453   int len, i, total_width;
2454   CGGlyph glyph;
2455   CGFloat ascent, descent, leading;
2457   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2458   if (! CONSP (val)
2459       || XTYPE (XCDR (val)) != Lisp_Misc
2460       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2461     return Qnil;
2462   font_name = XSAVE_POINTER (XCDR (val), 0);
2463   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2465   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2466   if (size == 0)
2467     size = pixel_size;
2469   block_input ();
2470   macfont = mac_font_create_with_name (font_name, size);
2471   if (macfont)
2472     {
2473       int fontsize = (int) [((NSFont *) macfont) pointSize];
2474       if (fontsize != size) size = fontsize;
2475     }
2476   unblock_input ();
2477   if (! macfont)
2478     return Qnil;
2480   font_object = font_make_object (VECSIZE (struct macfont_info), entity, size);
2481   ASET (font_object, FONT_TYPE_INDEX, macfont_driver.type);
2482   len = font_unparse_xlfd (entity, size, name, 256);
2483   if (len > 0)
2484     ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
2485   len = font_unparse_fcname (entity, size, name, 256);
2486   if (len > 0)
2487     ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
2488   else
2489     ASET (font_object, FONT_FULLNAME_INDEX,
2490           AREF (font_object, FONT_NAME_INDEX));
2491   font = XFONT_OBJECT (font_object);
2492   font->pixel_size = size;
2493   font->driver = &macfont_driver;
2494   font->encoding_charset = font->repertory_charset = -1;
2496   block_input ();
2498   macfont_info = (struct macfont_info *) font;
2499   macfont_info->macfont = macfont;
2500   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2502   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2503   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2504     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2505                                                                   size);
2506   else
2507     macfont_info->screen_font = NULL;
2508   macfont_info->cache = macfont_lookup_cache (font_name);
2509   macfont_retain_cache (macfont_info->cache);
2510   macfont_info->metrics = NULL;
2511   macfont_info->metrics_nrows = 0;
2512   macfont_info->synthetic_italic_p = 0;
2513   macfont_info->synthetic_bold_p = 0;
2514   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2515   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2516   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2517       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2518     macfont_info->synthetic_italic_p = 1;
2519   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2520       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2521     macfont_info->synthetic_bold_p = 1;
2522   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2523     macfont_info->spacing = MACFONT_SPACING_MONO;
2524   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2525            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2526                == FONT_SPACING_SYNTHETIC_MONO))
2527     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2528   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2529     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2530   else
2531     {
2532       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2533       if (CONSP (val))
2534         macfont_info->antialias =
2535           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2536     }
2537   macfont_info->color_bitmap_p = 0;
2538   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2539     macfont_info->color_bitmap_p = 1;
2541   glyph = macfont_get_glyph_for_character (font, ' ');
2542   if (glyph != kCGFontIndexInvalid)
2543     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2544   else
2545     /* dirty workaround */
2546     font->space_width = pixel_size;
2548   total_width = font->space_width;
2549   for (i = 1; i < 95; i++)
2550     {
2551       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2552       if (glyph == kCGFontIndexInvalid)
2553         break;
2554       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2555     }
2556   if (i == 95)
2557     font->average_width = total_width / 95;
2558   else
2559     font->average_width = font->space_width; /* XXX */
2561   if (!(macfont_info->screen_font
2562         && mac_screen_font_get_metrics (macfont_info->screen_font,
2563                                         &ascent, &descent, &leading)))
2564     {
2565       CFStringRef family_name;
2567       ascent = mac_font_get_ascent (macfont);
2568       descent = mac_font_get_descent (macfont);
2569       leading = mac_font_get_leading (macfont);
2570       /* AppKit and WebKit do some adjustment to the heights of
2571          Courier, Helvetica, and Times.  */
2572       family_name = mac_font_copy_family_name (macfont);
2573       if (family_name)
2574         {
2575           if ((CFStringCompare (family_name, CFSTR ("Courier"), 0)
2576                == kCFCompareEqualTo)
2577               || (CFStringCompare (family_name, CFSTR ("Helvetica"), 0)
2578                   == kCFCompareEqualTo)
2579               || (CFStringCompare (family_name, CFSTR ("Times"), 0)
2580                   == kCFCompareEqualTo))
2581             ascent += (ascent + descent) * .15f;
2582           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2583             {
2584               leading *= .25f;
2585               ascent += leading;
2586             }
2587           CFRelease (family_name);
2588         }
2589     }
2590   font->ascent = ascent + 0.5f;
2591   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2592   if (CONSP (val) && !NILP (XCDR (val)))
2593     font->descent = descent + 0.5f;
2594   else
2595     font->descent = descent + leading + 0.5f;
2596   font->height = font->ascent + font->descent;
2598   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2599   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2601   unblock_input ();
2603   /* Unfortunately Xft doesn't provide a way to get minimum char
2604      width.  So, we use space_width instead.  */
2605   font->min_width = font->max_width = font->space_width; /* XXX */
2607   font->baseline_offset = 0;
2608   font->relative_compose = 0;
2609   font->default_ascent = 0;
2610   font->vertical_centering = 0;
2612   return font_object;
2615 static void
2616 macfont_close (struct font *font)
2618   struct macfont_info *macfont_info = (struct macfont_info *) font;
2620   if (macfont_info->cache)
2621     {
2622       int i;
2624       block_input ();
2625       CFRelease (macfont_info->macfont);
2626       CGFontRelease (macfont_info->cgfont);
2627       if (macfont_info->screen_font)
2628         CFRelease (macfont_info->screen_font);
2629       macfont_release_cache (macfont_info->cache);
2630       for (i = 0; i < macfont_info->metrics_nrows; i++)
2631         if (macfont_info->metrics[i])
2632           xfree (macfont_info->metrics[i]);
2633       if (macfont_info->metrics)
2634         xfree (macfont_info->metrics);
2635       macfont_info->cache = NULL;
2636       unblock_input ();
2637     }
2640 static int
2641 macfont_has_char (Lisp_Object font, int c)
2643   int result;
2644   CFCharacterSetRef charset;
2646   block_input ();
2647   if (FONT_ENTITY_P (font))
2648     {
2649       Lisp_Object val;
2650       CFStringRef name;
2652       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2653       val = XCDR (val);
2654       name = XSAVE_POINTER (val, 0);
2655       charset = macfont_get_cf_charset_for_name (name);
2656     }
2657   else
2658     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2660   result = CFCharacterSetIsLongCharacterMember (charset, c);
2661   unblock_input ();
2663   return result;
2666 static unsigned
2667 macfont_encode_char (struct font *font, int c)
2669   struct macfont_info *macfont_info = (struct macfont_info *) font;
2670   CGGlyph glyph;
2672   block_input ();
2673   glyph = macfont_get_glyph_for_character (font, c);
2674   unblock_input ();
2676   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2679 static int
2680 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2681                       struct font_metrics *metrics)
2683   int width, i;
2685   block_input ();
2686   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2687   for (i = 1; i < nglyphs; i++)
2688     {
2689       struct font_metrics m;
2690       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2691                                      NULL, 0);
2693       if (metrics)
2694         {
2695           if (width + m.lbearing < metrics->lbearing)
2696             metrics->lbearing = width + m.lbearing;
2697           if (width + m.rbearing > metrics->rbearing)
2698             metrics->rbearing = width + m.rbearing;
2699           if (m.ascent > metrics->ascent)
2700             metrics->ascent = m.ascent;
2701           if (m.descent > metrics->descent)
2702             metrics->descent = m.descent;
2703         }
2704       width += w;
2705     }
2706   unblock_input ();
2708   if (metrics)
2709     metrics->width = width;
2711   return width;
2714 static int
2715 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2716               bool with_background)
2718   struct frame * f = s->f;
2719   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2720   FontRef macfont = macfont_info->macfont;
2721   CGContextRef context;
2722   BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2723   int end = isComposite ? s->cmp_to : s->nchars;
2724   int len = end - s->cmp_from;
2725   struct face *face = s->face;
2726   int i;
2728   block_input ();
2730   context = [[NSGraphicsContext currentContext] graphicsPort];
2731   CGContextSaveGState (context);
2733 #if 0
2734   if (s->num_clips > 0)
2735     {
2736       CGRect clips[2];
2738       for (i = 0; i < s->num_clips; i++)
2739         clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2740                                   s->clip[i].right - s->clip[i].left,
2741                                   s->clip[i].bottom - s->clip[i].top);
2742       CGContextClipToRects (context, clips, s->num_clips);
2743     }
2744 #endif
2746   if (with_background)
2747     {
2748       if (s->hl == DRAW_MOUSE_FACE) 
2749         {
2750           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2751           if (!face)
2752             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2753         }
2755       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2756       CGContextFillRect (context,
2757                          CGRectMake (x, y,
2758                                      s->width, FONT_HEIGHT (s->font)));
2759     }
2761   if (macfont_info->cgfont)
2762     {
2763       CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2764       CGPoint *positions = alloca (sizeof (CGPoint) * len);
2765       CGFloat total_width = 0;
2766       CGFloat font_size = mac_font_get_size (macfont);
2767       CGAffineTransform atfm;
2768       CGFloat advance_delta = 0;
2769       int y_draw = -s->ybase;
2770       int no_antialias_p =
2771         (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2772          || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2773              && font_size <= macfont_antialias_threshold));
2775       for (i = 0; i < len; i++)
2776         {
2777           int width;
2779           glyphs[i] = *(s->char2b + s->cmp_from + i);
2780           width = (s->padding_p ? 1
2781                    : macfont_glyph_extents (s->font, glyphs[i],
2782                                             NULL, &advance_delta,
2783                                             no_antialias_p));
2784           positions[i].x = total_width + advance_delta;
2785           positions[i].y = 0;
2786           total_width += width;
2787         }
2789       CGContextScaleCTM (context, 1, -1);
2790       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2791       if (macfont_info->synthetic_italic_p)
2792         atfm = synthetic_italic_atfm;
2793       else
2794         atfm = CGAffineTransformIdentity;
2795       if (macfont_info->synthetic_bold_p)
2796         {
2797           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2798           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2799           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2800         }
2801       if (no_antialias_p)
2802         CGContextSetShouldAntialias (context, false);
2804       CGContextSetTextMatrix (context, atfm);
2805       CGContextSetTextPosition (context, x, y_draw);
2807 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2808       if (macfont_info->color_bitmap_p
2809 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2810           && CTFontDrawGlyphs != NULL
2811 #endif
2812           )
2813         {
2814           if (len > 0)
2815             {
2816               CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2817             }
2818         }
2819       else
2820 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2821         {
2822           CGContextSetFont (context, macfont_info->cgfont);
2823           CGContextSetFontSize (context, font_size);
2824           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2825         }
2826     }
2828   CGContextRestoreGState (context);
2830   unblock_input ();
2832   return len;
2835 static Lisp_Object
2836 macfont_shape (Lisp_Object lgstring)
2838   struct font *font;
2839   struct macfont_info *macfont_info;
2840   FontRef macfont;
2841   ptrdiff_t glyph_len, len, i, j;
2842   CFIndex nonbmp_len;
2843   UniChar *unichars;
2844   CFIndex *nonbmp_indices;
2845   CFStringRef string;
2846   CFIndex used = 0;
2847   struct mac_glyph_layout *glyph_layouts;
2849   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2850   macfont_info = (struct macfont_info *) font;
2851   macfont = macfont_info->macfont;
2853   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2854   nonbmp_len = 0;
2855   for (i = 0; i < glyph_len; i++)
2856     {
2857       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2859       if (NILP (lglyph))
2860         break;
2861       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2862         nonbmp_len++;
2863     }
2865   len = i;
2867   if (INT_MAX / 2 < len)
2868     memory_full (SIZE_MAX);
2870   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2871   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2872   for (i = j = 0; i < len; i++)
2873     {
2874       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2876       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2877         {
2878           nonbmp_indices[j] = i + j;
2879           j++;
2880         }
2881     }
2882   nonbmp_indices[j] = len + j;  /* sentinel */
2884   block_input ();
2886   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2887                                                kCFAllocatorNull);
2888   if (string)
2889     {
2890       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2891       if (macfont_info->screen_font)
2892         used = mac_screen_font_shape (macfont_info->screen_font, string,
2893                                       glyph_layouts, glyph_len);
2894       else
2895         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2896       CFRelease (string);
2897     }
2899   unblock_input ();
2901   if (used == 0)
2902     return Qnil;
2904   block_input ();
2906   for (i = 0; i < used; i++)
2907     {
2908       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2909       struct mac_glyph_layout *gl = glyph_layouts + i;
2910       EMACS_INT from, to;
2911       struct font_metrics metrics;
2912       int xoff, yoff, wadjust;
2914       if (NILP (lglyph))
2915         {
2916           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2917           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2918         }
2920       from = gl->comp_range.location;
2921       /* Convert UTF-16 index to UTF-32.  */
2922       j = 0;
2923       while (nonbmp_indices[j] < from)
2924         j++;
2925       from -= j;
2926       LGLYPH_SET_FROM (lglyph, from);
2928       to = gl->comp_range.location + gl->comp_range.length;
2929       /* Convert UTF-16 index to UTF-32.  */
2930       while (nonbmp_indices[j] < to)
2931         j++;
2932       to -= j;
2933       LGLYPH_SET_TO (lglyph, to - 1);
2935       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2936          the composition is trivial.  */
2937       {
2938         UTF32Char c;
2940         if (unichars[gl->string_index] >= 0xD800
2941             && unichars[gl->string_index] < 0xDC00)
2942           c = (((unichars[gl->string_index] - 0xD800) << 10)
2943                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2944         else
2945           c = unichars[gl->string_index];
2946         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2947           c = 0;
2948         LGLYPH_SET_CHAR (lglyph, c);
2949       }
2951       {
2952         unsigned long cc = gl->glyph_id;
2953         LGLYPH_SET_CODE (lglyph, cc);
2954       }
2956       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2957       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2958       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2959       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2960       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2961       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2963       xoff = lround (gl->advance_delta);
2964       yoff = lround (- gl->baseline_delta);
2965       wadjust = lround (gl->advance);
2966       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2967         {
2968           Lisp_Object vec;
2970           vec = Fmake_vector (make_number (3), Qnil);
2971           ASET (vec, 0, make_number (xoff));
2972           ASET (vec, 1, make_number (yoff));
2973           ASET (vec, 2, make_number (wadjust));
2974           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2975         }
2976     }
2978   unblock_input ();
2980   return make_number (used);
2983 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2984 typedef UInt8 UINT24[3];
2986 #pragma pack(push, 1)
2987 struct variation_selector_record
2989   UINT24 var_selector;
2990   UInt32 default_uvs_offset, non_default_uvs_offset;
2992 struct uvs_table
2994   UInt16 format;
2995   UInt32 length, num_var_selector_records;
2996   struct variation_selector_record variation_selector_records[1];
2998 #define SIZEOF_UVS_TABLE_HEADER \
2999   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3001 struct unicode_value_range
3003   UINT24 start_unicode_value;
3004   UInt8 additional_count;
3006 struct default_uvs_table {
3007   UInt32 num_unicode_value_ranges;
3008   struct unicode_value_range unicode_value_ranges[1];
3010 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3011   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3013 struct uvs_mapping
3015   UINT24 unicode_value;
3016   UInt16 glyph_id;
3018 struct non_default_uvs_table
3020   UInt32 num_uvs_mappings;
3021   struct uvs_mapping uvs_mappings[1];
3023 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3024   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3025 #pragma pack(pop)
3027 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3028 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3029    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3030    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3031 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3032 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3033 /* Succeeding one byte should also be accessible.  */
3034 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3035 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3037 /* Return UVS subtable for the specified FONT.  If the subtable is not
3038    found or ill-formatted, then return NULL.  */
3040 static CFDataRef
3041 mac_font_copy_uvs_table (FontRef font)
3043   CFDataRef cmap_table, uvs_table = NULL;
3045   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3046   if (cmap_table)
3047     {
3048       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3049       struct uvs_table *uvs;
3050       struct variation_selector_record *records;
3051       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3053 #if __LP64__
3054       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3055         goto finish;
3056 #endif
3058       cmap_len = CFDataGetLength (cmap_table);
3059       if (sizeof_sfntCMapHeader > cmap_len)
3060         goto finish;
3062       ntables = BUINT16_VALUE (cmap->numTables);
3063       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3064                      / sizeof_sfntCMapEncoding))
3065         goto finish;
3067       for (i = 0; i < ntables; i++)
3068         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3069              == kFontUnicodePlatform)
3070             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3071                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3072           {
3073             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3074             break;
3075           }
3076       if (i == ntables
3077           || uvs_offset > cmap_len
3078           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3079         goto finish;
3081       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3082       uvs_len = BUINT32_VALUE (uvs->length);
3083       if (uvs_len > cmap_len - uvs_offset
3084           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3085         goto finish;
3087       if (BUINT16_VALUE (uvs->format) != 14)
3088         goto finish;
3090       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3091       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3092                       / sizeof (struct variation_selector_record)))
3093         goto finish;
3095       records = uvs->variation_selector_records;
3096       for (i = 0; i < nrecords; i++)
3097         {
3098           UInt32 default_uvs_offset, non_default_uvs_offset;
3100           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3101           if (default_uvs_offset)
3102             {
3103               struct default_uvs_table *default_uvs;
3104               UInt32 nranges;
3106               if (default_uvs_offset > uvs_len
3107                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3108                       > uvs_len - default_uvs_offset))
3109                 goto finish;
3111               default_uvs = ((struct default_uvs_table *)
3112                              ((UInt8 *) uvs + default_uvs_offset));
3113               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3114               if (nranges > ((uvs_len - default_uvs_offset
3115                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3116                              / sizeof (struct unicode_value_range)))
3117                 goto finish;
3118               /* Now 2 * nranges can't overflow, so we can safely use
3119                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3120                  mac_font_get_glyphs_for_variants.  */
3121             }
3123           non_default_uvs_offset =
3124             BUINT32_VALUE (records[i].non_default_uvs_offset);
3125           if (non_default_uvs_offset)
3126             {
3127               struct non_default_uvs_table *non_default_uvs;
3128               UInt32 nmappings;
3130               if (non_default_uvs_offset > uvs_len
3131                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3132                       > uvs_len - non_default_uvs_offset))
3133                 goto finish;
3135               non_default_uvs = ((struct non_default_uvs_table *)
3136                                  ((UInt8 *) uvs + non_default_uvs_offset));
3137               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3138               if (nmappings > ((uvs_len - non_default_uvs_offset
3139                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3140                                / sizeof (struct uvs_mapping)))
3141                 goto finish;
3142               /* Now 2 * nmappings can't overflow, so we can safely
3143                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3144                  in mac_font_get_glyphs_for_variants.  */
3145             }
3146         }
3148       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3150     finish:
3151       CFRelease (cmap_table);
3152     }
3154   return uvs_table;
3157 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3158    sequence consisting of the given base character C and each
3159    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3160    result (explained below) into the corresponding GLYPHS[i].  If the
3161    entry is found in the Default UVS Table, then the result is 0.  If
3162    the entry is found in the Non-Default UVS Table, then the result is
3163    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3164    elements in SELECTORS must be sorted in strictly increasing
3165    order.  */
3167 static void
3168 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3169                                   const UTF32Char selectors[], CGGlyph glyphs[],
3170                                   CFIndex count)
3172   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3173   struct variation_selector_record *records = uvs->variation_selector_records;
3174   CFIndex i;
3175   UInt32 ir, nrecords;
3176 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3177   dispatch_queue_t queue =
3178     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3179   dispatch_group_t group = dispatch_group_create ();
3180 #endif
3182   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3183   i = 0;
3184   ir = 0;
3185   while (i < count && ir < nrecords)
3186     {
3187       UInt32 default_uvs_offset, non_default_uvs_offset;
3189       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3190         {
3191           glyphs[i++] = kCGFontIndexInvalid;
3192           continue;
3193         }
3194       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3195         {
3196           ir++;
3197           continue;
3198         }
3200       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3201       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3202       non_default_uvs_offset =
3203         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3204 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3205       dispatch_group_async (group, queue, ^{
3206 #endif
3207           glyphs[i] = kCGFontIndexInvalid;
3209           if (default_uvs_offset)
3210             {
3211               struct default_uvs_table *default_uvs =
3212                 (struct default_uvs_table *) ((UInt8 *) uvs
3213                                               + default_uvs_offset);
3214               struct unicode_value_range *ranges =
3215                 default_uvs->unicode_value_ranges;
3216               UInt32 lo, hi;
3218               lo = 0;
3219               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3220               while (lo < hi)
3221                 {
3222                   UInt32 mid = (lo + hi) / 2;
3224                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3225                     hi = mid;
3226                   else
3227                     lo = mid + 1;
3228                 }
3229               if (hi > 0
3230                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3231                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3232                 glyphs[i] = 0;
3233             }
3235           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3236             {
3237               struct non_default_uvs_table *non_default_uvs =
3238                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3239                                                   + non_default_uvs_offset);
3240               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3241               UInt32 lo, hi;
3243               lo = 0;
3244               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3245               while (lo < hi)
3246                 {
3247                   UInt32 mid = (lo + hi) / 2;
3249                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3250                     hi = mid;
3251                   else
3252                     lo = mid + 1;
3253                 }
3254               if (hi > 0 &&
3255                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3256                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3257             }
3258 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3259         });
3260 #endif
3261       i++;
3262       ir++;
3263     }
3264   while (i < count)
3265     glyphs[i++] = kCGFontIndexInvalid;
3266 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3267   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3268   dispatch_release (group);
3269 #endif
3272 static int
3273 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3275   CFDataRef uvs_table;
3276   CharacterCollection uvs_collection;
3277   int i, n = 0;
3279   block_input ();
3280   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3282   if (uvs_table)
3283     {
3284       UTF32Char selectors[256];
3285       CGGlyph glyphs[256];
3287       for (i = 0; i < 16; i++)
3288         selectors[i] = 0xFE00 + i;
3289       for (; i < 256; i++)
3290         selectors[i] = 0xE0100 + (i - 16);
3291       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3292       for (i = 0; i < 256; i++)
3293         {
3294           CGGlyph glyph = glyphs[i];
3296           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3297               && glyph != kCGFontIndexInvalid)
3298             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3299           if (glyph == kCGFontIndexInvalid)
3300             variations[i] = 0;
3301           else
3302             {
3303               variations[i] = (glyph ? glyph
3304                                : macfont_get_glyph_for_character (font, c));
3305               n++;
3306             }
3307         }
3308     }
3309   unblock_input ();
3311   return n;
3314 static const char *const macfont_booleans[] = {
3315   ":antialias",
3316   ":minspace",
3317   NULL,
3320 static const char *const macfont_non_booleans[] = {
3321   ":lang",
3322   ":script",
3323   ":destination",
3324   NULL,
3327 static void
3328 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3330   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3333 static Boolean
3334 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3335                                           CFArrayRef languages)
3337   Boolean result = true;
3338   CFArrayRef desc_languages =
3339     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3341   if (desc_languages == NULL)
3342     result = false;
3343   else
3344     {
3345       CFIndex desc_languages_count, i, languages_count;
3347       desc_languages_count = CFArrayGetCount (desc_languages);
3348       languages_count = CFArrayGetCount (languages);
3349       for (i = 0; i < languages_count; i++)
3350         if (!CFArrayContainsValue (desc_languages,
3351                                    CFRangeMake (0, desc_languages_count),
3352                                    CFArrayGetValueAtIndex (languages, i)))
3353           {
3354             result = false;
3355             break;
3356           }
3357       CFRelease (desc_languages);
3358     }
3360   return result;
3363 static CFStringRef
3364 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3366   CFStringRef result = NULL;
3367   CFStringRef charset_string =
3368     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3370   if (charset_string && CFStringGetLength (charset_string) > 0)
3371     {
3372       CFStringRef keys[] = {
3373 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3374         kCTLanguageAttributeName
3375 #else
3376         CFSTR ("NSLanguage")
3377 #endif
3378       };
3379       CFTypeRef values[] = {NULL};
3380       CFIndex num_values = 0;
3381       CFArrayRef languages
3382         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3384       if (languages && CFArrayGetCount (languages) > 0)
3385         {
3386           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3387             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3388           else
3389             {
3390               CFCharacterSetRef charset =
3391                 CFDictionaryGetValue (attributes,
3392                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3394               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3395             }
3396         }
3397       if (result == NULL)
3398         {
3399           CFAttributedStringRef attr_string = NULL;
3400           CTLineRef ctline = NULL;
3401           CFDictionaryRef attrs
3402             = CFDictionaryCreate (NULL, (const void **) keys,
3403                                   (const void **) values, num_values,
3404                                   &kCFTypeDictionaryKeyCallBacks,
3405                                   &kCFTypeDictionaryValueCallBacks);
3407           if (attrs)
3408             {
3409               attr_string = CFAttributedStringCreate (NULL, charset_string,
3410                                                       attrs);
3411               CFRelease (attrs);
3412             }
3413           if (attr_string)
3414             {
3415               ctline = CTLineCreateWithAttributedString (attr_string);
3416               CFRelease (attr_string);
3417             }
3418           if (ctline)
3419             {
3420               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3421               CFIndex i, nruns = CFArrayGetCount (runs);
3422               CTFontRef font;
3424               for (i = 0; i < nruns; i++)
3425                 {
3426                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3427                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3428                   CTFontRef font_in_run;
3430                   if (attributes == NULL)
3431                     break;
3432                   font_in_run =
3433                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3434                   if (font_in_run == NULL)
3435                     break;
3436                   if (i == 0)
3437                     font = font_in_run;
3438                   else if (!mac_ctfont_equal_in_postscript_name (font,
3439                                                                  font_in_run))
3440                     break;
3441                 }
3442               if (nruns > 0 && i == nruns)
3443                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3444               CFRelease (ctline);
3445             }
3446         }
3447     }
3449   return result;
3452 static inline double
3453 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3455   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3456                                      &glyph, NULL, 1);
3459 static inline CGRect
3460 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3462   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3463                                           &glyph, NULL, 1);
3466 static CFArrayRef
3467 mac_ctfont_create_available_families (void)
3469   CFMutableArrayRef families = NULL;
3471 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3472 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3473   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3474 #endif
3475     {
3476       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3478       if (orig_families)
3479         {
3480           CFIndex i, count = CFArrayGetCount (orig_families);
3482           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3483           if (families)
3484             for (i = 0; i < count; i++)
3485               {
3486                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3488                 if (!CFStringHasPrefix (family, CFSTR ("."))
3489                     && (CTFontManagerCompareFontFamilyNames (family,
3490                                                              CFSTR ("LastResort"),
3491                                                              NULL)
3492                         != kCFCompareEqualTo))
3493                   CFArrayAppendValue (families, family);
3494               }
3495           CFRelease (orig_families);
3496         }
3497     }
3498 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3499   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3500 #endif
3501 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3502 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3503     {
3504       CTFontCollectionRef collection;
3505       CFArrayRef descs = NULL;
3507       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3508       if (collection)
3509         {
3510           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3511           CFRelease (collection);
3512         }
3513       if (descs)
3514         {
3515           CFIndex i, count = CFArrayGetCount (descs);
3517           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3518           if (families)
3519             for (i = 0; i < count; i++)
3520               {
3521                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3522                 CFStringRef name =
3523                   mac_font_descriptor_copy_attribute (desc,
3524                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3526                 if (name)
3527                   {
3528                     CFIndex p, limit = CFArrayGetCount (families);
3530                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3531                                               (const void *) name,
3532                                               mac_font_family_compare, NULL);
3533                     if (p >= limit)
3534                       CFArrayAppendValue (families, name);
3535                     else if (mac_font_family_compare
3536                              (CFArrayGetValueAtIndex (families, p),
3537                               name, NULL) != kCFCompareEqualTo)
3538                       CFArrayInsertValueAtIndex (families, p, name);
3539                     CFRelease (name);
3540                   }
3541               }
3542           CFRelease (descs);
3543         }
3544     }
3545 #endif
3547   return families;
3550 static Boolean
3551 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3553   Boolean result;
3554   CFStringRef name1, name2;
3556   if (font1 == font2)
3557     return true;
3559   result = false;
3560   name1 = CTFontCopyPostScriptName (font1);
3561   if (name1)
3562     {
3563       name2 = CTFontCopyPostScriptName (font2);
3564       if (name2)
3565         {
3566           result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3567           CFRelease (name2);
3568         }
3569       CFRelease (name1);
3570     }
3572   return result;
3575 static CTLineRef
3576 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3577                                              CTFontRef macfont)
3579   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3580   CFTypeRef values[] = {NULL, NULL};
3581   CFDictionaryRef attributes = NULL;
3582   CFAttributedStringRef attr_string = NULL;
3583   CTLineRef ctline = NULL;
3584   float float_zero = 0.0f;
3586   values[0] = macfont;
3587   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3588   if (values[1])
3589     {
3590       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3591                                        (const void **) values,
3592                                        sizeof (keys) / sizeof (keys[0]),
3593                                        &kCFTypeDictionaryKeyCallBacks,
3594                                        &kCFTypeDictionaryValueCallBacks);
3595       CFRelease (values[1]);
3596     }
3597   if (attributes)
3598     {
3599       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3600       CFRelease (attributes);
3601     }
3602   if (attr_string)
3603     {
3604       ctline = CTLineCreateWithAttributedString (attr_string);
3605       CFRelease (attr_string);
3606     }
3607   if (ctline)
3608     {
3609       /* Abandon if ctline contains some fonts other than the
3610          specified one.  */
3611       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3612       CFIndex i, nruns = CFArrayGetCount (runs);
3614       for (i = 0; i < nruns; i++)
3615         {
3616           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3617           CFDictionaryRef attributes = CTRunGetAttributes (run);
3618           CTFontRef font_in_run;
3620           if (attributes == NULL)
3621             break;
3622           font_in_run =
3623             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3624           if (font_in_run == NULL)
3625             break;
3626           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3627             break;
3628         }
3629       if (i < nruns)
3630         {
3631           CFRelease (ctline);
3632           ctline = NULL;
3633         }
3634     }
3636   return ctline;
3639 static CFIndex
3640 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3641                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3643   CFIndex used, result = 0;
3644   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3646   if (ctline == NULL)
3647     return 0;
3649   used = CTLineGetGlyphCount (ctline);
3650   if (used <= glyph_len)
3651     {
3652       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3653       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3654       CGFloat total_advance = 0;
3655       CFIndex total_glyph_count = 0;
3657       for (k = 0; k < ctrun_count; k++)
3658         {
3659           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3660           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3661           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3662           CFRange string_range, comp_range, range;
3663           CFIndex *permutation;
3665           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3666             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3667           else
3668             permutation = NULL;
3670 #define RIGHT_TO_LEFT_P permutation
3672           /* Now the `comp_range' member of struct mac_glyph_layout is
3673              temporarily used as a work area such that:
3674               glbuf[i].comp_range.location =
3675                 min {compRange[i + 1].location, ...,
3676                      compRange[glyph_count - 1].location,
3677                      maxRange (stringRangeForCTRun)}
3678               glbuf[i].comp_range.length = maxRange (compRange[i])
3679              where compRange[i] is the range of composed characters
3680              containing i-th glyph.  */
3681           string_range = CTRunGetStringRange (ctrun);
3682           min_location = string_range.location + string_range.length;
3683           for (i = 0; i < glyph_count; i++)
3684             {
3685               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3686               CFIndex glyph_index;
3687               CFRange rng;
3689               if (!RIGHT_TO_LEFT_P)
3690                 glyph_index = glyph_count - i - 1;
3691               else
3692                 glyph_index = i;
3693               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3694                                      &gl->string_index);
3695               rng =
3696                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3697                                                              gl->string_index);
3698               gl->comp_range.location = min_location;
3699               gl->comp_range.length = rng.location + rng.length;
3700               if (rng.location < min_location)
3701                 min_location = rng.location;
3702             }
3704           /* Fill the `comp_range' member of struct mac_glyph_layout,
3705              and setup a permutation for right-to-left text.  */
3706           comp_range = CFRangeMake (string_range.location, 0);
3707           range = CFRangeMake (0, 0);
3708           while (1)
3709             {
3710               struct mac_glyph_layout *gl =
3711                 glbuf + range.location + range.length;
3713               if (gl->comp_range.length
3714                   > comp_range.location + comp_range.length)
3715                 comp_range.length = gl->comp_range.length - comp_range.location;
3716               min_location = gl->comp_range.location;
3717               range.length++;
3719               if (min_location >= comp_range.location + comp_range.length)
3720                 {
3721                   comp_range.length = min_location - comp_range.location;
3722                   for (i = 0; i < range.length; i++)
3723                     {
3724                       glbuf[range.location + i].comp_range = comp_range;
3725                       if (RIGHT_TO_LEFT_P)
3726                         permutation[range.location + i] =
3727                           range.location + range.length - i - 1;
3728                     }
3730                   comp_range = CFRangeMake (min_location, 0);
3731                   range.location += range.length;
3732                   range.length = 0;
3733                   if (range.location == glyph_count)
3734                     break;
3735                 }
3736             }
3738           /* Then fill the remaining members.  */
3739           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3740                range.location++)
3741             {
3742               struct mac_glyph_layout *gl;
3743               CGPoint position;
3745               if (!RIGHT_TO_LEFT_P)
3746                 gl = glbuf + range.location;
3747               else
3748                 {
3749                   CFIndex src, dest;
3751                   src = glyph_count - 1 - range.location;
3752                   dest = permutation[src];
3753                   gl = glbuf + dest;
3754                   if (src < dest)
3755                     {
3756                       CFIndex tmp = gl->string_index;
3758                       gl->string_index = glbuf[src].string_index;
3759                       glbuf[src].string_index = tmp;
3760                     }
3761                 }
3762               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3764               CTRunGetPositions (ctrun, range, &position);
3765               gl->advance_delta = position.x - total_advance;
3766               gl->baseline_delta = position.y;
3767               gl->advance = (gl->advance_delta
3768                              + CTRunGetTypographicBounds (ctrun, range,
3769                                                           NULL, NULL, NULL));
3770               total_advance += gl->advance;
3771             }
3773           if (RIGHT_TO_LEFT_P)
3774             xfree (permutation);
3776 #undef RIGHT_TO_LEFT_P
3778           total_glyph_count += glyph_count;
3779         }
3781       result = used;
3782     }
3783   CFRelease (ctline);
3785   return result;
3788 /* The function below seems to cause a memory leak for the CFString
3789    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3790    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3791 #if USE_CT_GLYPH_INFO
3792 static CGGlyph
3793 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3794                               CGFontIndex cid)
3796   CGGlyph result = kCGFontIndexInvalid;
3797   UniChar characters[] = {0xfffd};
3798   CFStringRef string;
3799   CFAttributedStringRef attr_string = NULL;
3800   CTLineRef ctline = NULL;
3802   string = CFStringCreateWithCharacters (NULL, characters,
3803                                          sizeof (characters)
3804                                          / sizeof (characters[0]));
3805   if (string)
3806     {
3807       CTGlyphInfoRef glyph_info =
3808         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3809       CFDictionaryRef attributes = NULL;
3811       if (glyph_info)
3812         {
3813           CFStringRef keys[] = {kCTFontAttributeName,
3814                                 kCTGlyphInfoAttributeName};
3815           CFTypeRef values[] = {font, glyph_info};
3817           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3818                                            (const void **) values,
3819                                            sizeof (keys) / sizeof (keys[0]),
3820                                            &kCFTypeDictionaryKeyCallBacks,
3821                                            &kCFTypeDictionaryValueCallBacks);
3822           CFRelease (glyph_info);
3823         }
3824       if (attributes)
3825         {
3826           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3827           CFRelease (attributes);
3828         }
3829       CFRelease (string);
3830     }
3831   if (attr_string)
3832     {
3833       ctline = CTLineCreateWithAttributedString (attr_string);
3834       CFRelease (attr_string);
3835     }
3836   if (ctline)
3837     {
3838       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3840       if (CFArrayGetCount (runs) > 0)
3841         {
3842           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3843           CFDictionaryRef attributes = CTRunGetAttributes (run);
3845           if (attributes)
3846             {
3847               CTFontRef font_in_run =
3848                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3850               if (font_in_run
3851                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3852                 {
3853                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3854                   if (result >= CTFontGetGlyphCount (font))
3855                     result = kCGFontIndexInvalid;
3856                 }
3857             }
3858         }
3859       CFRelease (ctline);
3860     }
3862   return result;
3864 #endif
3866 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3867 static inline int
3868 mac_font_family_group (CFStringRef family)
3870   if (CFStringHasPrefix (family, CFSTR ("#")))
3871     return 2;
3872   else
3873     {
3874       CFRange range;
3876       range = CFStringFind (family, CFSTR ("Apple"),
3877                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3878       if (range.location != kCFNotFound)
3879         return 1;
3881       return 0;
3882     }
3885 static CFComparisonResult
3886 mac_font_family_compare (const void *val1, const void *val2, void *context)
3888   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3889   int group1, group2;
3891   group1 = mac_font_family_group (family1);
3892   group2 = mac_font_family_group (family2);
3893   if (group1 < group2)
3894     return kCFCompareLessThan;
3895   if (group1 > group2)
3896     return kCFCompareGreaterThan;
3897   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3899 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3901 static CFArrayRef
3902 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3904   CFArrayRef result = NULL;
3906 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3907 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3908   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3909 #endif
3910     {
3911       CTFontRef user_font =
3912         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3914       if (user_font)
3915         {
3916           CFArrayRef languages =
3917             CFArrayCreate (NULL, (const void **) &language, 1,
3918                            &kCFTypeArrayCallBacks);
3920           if (languages)
3921             {
3922               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3923                                                                  languages);
3924               CFRelease (languages);
3925             }
3926           CFRelease (user_font);
3927         }
3928     }
3929 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3930   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3931 #endif
3932 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3933 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3934     {
3935       CFIndex i;
3937       for (i = 0; macfont_language_default_font_names[i].language; i++)
3938         {
3939           if (CFStringCompare (macfont_language_default_font_names[i].language,
3940                                language, 0) == kCFCompareEqualTo)
3941             {
3942               CFMutableArrayRef descriptors =
3943                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3945               if (descriptors)
3946                 {
3947                   CFIndex j;
3949                   for (j = 0;
3950                        macfont_language_default_font_names[i].font_names[j];
3951                        j++)
3952                     {
3953                       CFDictionaryRef attributes =
3954                         CFDictionaryCreate (NULL,
3955                                             ((const void **)
3956                                              &MAC_FONT_NAME_ATTRIBUTE),
3957                                             ((const void **)
3958                                              &macfont_language_default_font_names[i].font_names[j]),
3959                                             1, &kCFTypeDictionaryKeyCallBacks,
3960                                             &kCFTypeDictionaryValueCallBacks);
3962                       if (attributes)
3963                         {
3964                           FontDescriptorRef pat_desc =
3965                             mac_font_descriptor_create_with_attributes (attributes);
3967                           if (pat_desc)
3968                             {
3969                               FontDescriptorRef descriptor =
3970                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3972                               if (descriptor)
3973                                 {
3974                                   CFArrayAppendValue (descriptors, descriptor);
3975                                   CFRelease (descriptor);
3976                                 }
3977                               CFRelease (pat_desc);
3978                             }
3979                           CFRelease (attributes);
3980                         }
3981                     }
3982                   result = descriptors;
3983                 }
3984               break;
3985             }
3986         }
3987     }
3988 #endif
3990   return result;
3993 static CFStringRef
3994 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3995                                                       CFArrayRef languages)
3997   CFStringRef result = NULL;
3998   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3999   CFArrayRef descriptors =
4000     mac_font_copy_default_descriptors_for_language (language);
4002   if (descriptors)
4003     {
4004       CFIndex i, count = CFArrayGetCount (descriptors);
4006       for (i = 0; i < count; i++)
4007         {
4008           FontDescriptorRef descriptor =
4009             CFArrayGetValueAtIndex (descriptors, i);
4011           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4012                                                         Qnil, languages))
4013             {
4014               CFStringRef family =
4015                 mac_font_descriptor_copy_attribute (descriptor,
4016                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4017               if (family)
4018                 {
4019                   if (!CFStringHasPrefix (family, CFSTR ("."))
4020                       && (CFStringCompare (family, CFSTR ("LastResort"), 0)
4021                           != kCFCompareEqualTo))
4022                     {
4023                       result = family;
4024                       break;
4025                     }
4026                   else
4027                     CFRelease (family);
4028                 }
4029             }
4030         }
4031       CFRelease (descriptors);
4032     }
4034   return result;
4037 void *
4038 macfont_get_nsctfont (struct font *font)
4040   struct macfont_info *macfont_info = (struct macfont_info *) font;
4041   FontRef macfont = macfont_info->macfont;
4043   return (void *) macfont;
4046 void
4047 mac_register_font_driver (struct frame *f)
4049   register_font_driver (&macfont_driver, f);
4052 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4055 void
4056 syms_of_macfont (void)
4058 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4059   static struct font_driver mac_font_driver;
4061   DEFSYM (Qmac_ct, "mac-ct");
4062   macfont_driver.type = Qmac_ct;
4063   register_font_driver (&macfont_driver, NULL);
4065   DEFSYM (QCdestination, ":destination");
4066   DEFSYM (QCminspace, ":minspace");
4067 #endif