Update copyright year to 2014 by running admin/update-copyright.
[emacs.git] / src / macfont.m
blob80088b31256cbdcbdcc60e7d55904f6de2141f97
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 "nsgui.h"
34 #include "nsterm.h"
35 #include "macfont.h"
36 #include "macuvs.h"
38 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
40 #include <libkern/OSByteOrder.h>
42 static struct font_driver macfont_driver;
44 /* Core Text, for Mac OS X 10.5 and later.  */
45 static Lisp_Object Qmac_ct;
47 static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
48 static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
49 static CFArrayRef mac_ctfont_create_available_families (void);
50 static Boolean mac_ctfont_equal_in_postscript_name (CTFontRef, CTFontRef);
51 static CTLineRef mac_ctfont_create_line_with_string_and_font (CFStringRef,
52                                                               CTFontRef);
53 static CFComparisonResult mac_font_family_compare (const void *,
54                                                    const void *, void *);
55 static Boolean mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef,
56                                                          CFArrayRef);
57 static CFStringRef mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef);
58 static CFIndex mac_ctfont_shape (CTFontRef, CFStringRef,
59                                  struct mac_glyph_layout *, CFIndex);
60 static CFArrayRef
61 mac_font_copy_default_descriptors_for_language (CFStringRef language);
63 static CFStringRef
64 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
65                                                       CFArrayRef languages);
67 #if USE_CT_GLYPH_INFO
68 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef,
69                                              CTCharacterCollection,
70                                              CGFontIndex);
71 #endif
73 /* The font property key specifying the font design destination.  The
74    value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
75    text.  (See the documentation of X Logical Font Description
76    Conventions.)  In the Mac font driver, 1 means the screen font is
77    used for calculating some glyph metrics.  You can see the
78    difference with Monaco 8pt or 9pt, for example.  */
79 static Lisp_Object QCdestination;
81 /* The boolean-valued font property key specifying the use of
82    leading.  */
83 static Lisp_Object QCminspace;
85 struct macfont_metrics;
87 /* The actual structure for Mac font that can be casted to struct font.  */
89 struct macfont_info
91   struct font font;
92   FontRef macfont;
93   CGFontRef cgfont;
94   ScreenFontRef screen_font;
95   struct macfont_cache *cache;
96   struct macfont_metrics **metrics;
97   short metrics_nrows;
98   bool_bf synthetic_italic_p : 1;
99   bool_bf synthetic_bold_p : 1;
100   unsigned spacing : 2;
101   unsigned antialias : 2;
102   bool_bf color_bitmap_p : 1;
105 /* Values for the `spacing' member in `struct macfont_info'.  */
107 enum
108   {
109     MACFONT_SPACING_PROPORTIONAL,
110     MACFONT_SPACING_MONO,
111     MACFONT_SPACING_SYNTHETIC_MONO,
112   };
114 /* Values for the `antialias' member in `struct macfont_info'.  */
116 enum
117   {
118     MACFONT_ANTIALIAS_DEFAULT,
119     MACFONT_ANTIALIAS_OFF,
120     MACFONT_ANTIALIAS_ON,
121   };
123 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
124 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
125 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
127 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
128 static const CGFloat synthetic_bold_factor = 0.024;
130 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
131                                                         FontSymbolicTraits *);
132 static void macfont_store_descriptor_attributes (FontDescriptorRef,
133                                                  Lisp_Object);
134 static Lisp_Object macfont_descriptor_entity (FontDescriptorRef,
135                                               Lisp_Object,
136                                               FontSymbolicTraits);
137 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
138 static int macfont_glyph_extents (struct font *, CGGlyph,
139                                   struct font_metrics *, CGFloat *, int);
140 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
141 static Boolean macfont_supports_charset_and_languages_p (FontDescriptorRef,
142                                                          CFCharacterSetRef,
143                                                          Lisp_Object,
144                                                          CFArrayRef);
145 static CFIndex macfont_closest_traits_index (CFArrayRef,
146                                              FontSymbolicTraits);
147 static CFDataRef mac_font_copy_uvs_table (FontRef);
148 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
149                                               const UTF32Char [],
150                                               CGGlyph [], CFIndex);
152 /* From CFData to a lisp string.  Always returns a unibyte string.  */
154 static Lisp_Object
155 cfdata_to_lisp (CFDataRef data)
157   CFIndex len = CFDataGetLength (data);
158   Lisp_Object result = make_uninit_string (len);
160   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
162   return result;
167 /* From CFString to a lisp string.  Returns a unibyte string
168    containing a UTF-8 byte sequence.  */
170 static Lisp_Object
171 cfstring_to_lisp_nodecode (CFStringRef string)
173   Lisp_Object result = Qnil;
174   CFDataRef data;
175   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
177   if (s)
178     {
179       CFIndex i, length = CFStringGetLength (string);
181       for (i = 0; i < length; i++)
182         if (CFStringGetCharacterAtIndex (string, i) == 0)
183           break;
185       if (i == length)
186         return make_unibyte_string (s, strlen (s));
187     }
189   data = CFStringCreateExternalRepresentation (NULL, string,
190                                                kCFStringEncodingUTF8, '?');
191   if (data)
192     {
193       result = cfdata_to_lisp (data);
194       CFRelease (data);
195     }
197   return result;
200 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
201    cfstring_create_with_utf8_cstring, this function preserves NUL
202    characters.  */
204 static CFStringRef
205 cfstring_create_with_string_noencode (Lisp_Object s)
207   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
208                                                 kCFStringEncodingUTF8, false);
210   if (string == NULL)
211     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
212     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
213                                       kCFStringEncodingMacRoman, false);
215   return string;
218 static CGFloat
219 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
221   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
223   return advancement.width;
226 static CGGlyph
227 mac_font_get_glyph_for_cid (FontRef font, CharacterCollection collection,
228                             CGFontIndex cid)
230 #if USE_CT_GLYPH_INFO
231   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
232 #else
233   {
234     CGGlyph result = kCGFontIndexInvalid;
235     NSFont *nsFont = (NSFont *) font;
236     unichar characters[] = {0xfffd};
237     NSString *string =
238       [NSString stringWithCharacters:characters
239                               length:(sizeof (characters)
240                                       / sizeof (characters[0]))];
241     NSGlyphInfo *glyphInfo =
242       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
243                                          collection:collection
244                                          baseString:string];
245     NSDictionary *attributes =
246       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
247                     glyphInfo,NSGlyphInfoAttributeName,nil];
248     NSTextStorage *textStorage =
249       [[NSTextStorage alloc] initWithString:string
250                                  attributes:attributes];
251     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
252     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
253     NSFont *fontInTextStorage;
255     [layoutManager addTextContainer:textContainer];
256     [textContainer release];
257     [textStorage addLayoutManager:layoutManager];
258     [layoutManager release];
260     /* Force layout.  */
261     (void) [layoutManager glyphRangeForTextContainer:textContainer];
263     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
264                                 effectiveRange:NULL];
265     if (fontInTextStorage == nsFont
266         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
267       {
268         NSGlyph glyph = [layoutManager glyphAtIndex:0];
270         if (glyph < [nsFont numberOfGlyphs])
271           result = glyph;
272       }
274     [textStorage release];
276     return result;
277   }
279 #endif
281 static ScreenFontRef
282 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
284   NSFont *result, *font;
286   font = [NSFont fontWithName:((NSString *) name) size:size];
287   result = [font screenFont];
289   return (ScreenFontRef)[result retain];
293 static Boolean
294 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
295                              CGFloat *descent, CGFloat *leading)
297   NSFont *nsFont = [(NSFont *)font printerFont];
298   NSTextStorage *textStorage;
299   NSLayoutManager *layoutManager;
300   NSTextContainer *textContainer;
301   NSRect usedRect;
302   NSPoint spaceLocation;
303   CGFloat descender;
305   textStorage = [[NSTextStorage alloc] initWithString:@" "];
306   layoutManager = [[NSLayoutManager alloc] init];
307   textContainer = [[NSTextContainer alloc] init];
309   [textStorage setFont:nsFont];
310   [textContainer setLineFragmentPadding:0];
311   [layoutManager setUsesScreenFonts:YES];
313   [layoutManager addTextContainer:textContainer];
314   [textContainer release];
315   [textStorage addLayoutManager:layoutManager];
316   [layoutManager release];
318   if (!(textStorage && layoutManager && textContainer))
319     {
320       [textStorage release];
322       return false;
323     }
325   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
326                                                  effectiveRange:NULL];
327   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
328   [textStorage release];
330   *ascent = spaceLocation.y;
331   *descent = NSHeight (usedRect) - spaceLocation.y;
332   *leading = 0;
333   descender = [nsFont descender];
334   if (- descender < *descent)
335     {
336       *leading = *descent + descender;
337       *descent = - descender;
338     }
340   return true;
343 static CFIndex
344 mac_font_shape_1 (NSFont *font, NSString *string,
345                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
346                   BOOL screen_font_p)
348   NSUInteger i;
349   CFIndex result = 0;
350   NSTextStorage *textStorage;
351   NSLayoutManager *layoutManager;
352   NSTextContainer *textContainer;
353   NSUInteger stringLength;
354   NSPoint spaceLocation;
355   NSUInteger used, numberOfGlyphs;
357   textStorage = [[NSTextStorage alloc] initWithString:string];
358   layoutManager = [[NSLayoutManager alloc] init];
359   textContainer = [[NSTextContainer alloc] init];
361   /* Append a trailing space to measure baseline position.  */
362   [textStorage appendAttributedString:([[[NSAttributedString alloc]
363                                           initWithString:@" "] autorelease])];
364   [textStorage setFont:font];
365   [textContainer setLineFragmentPadding:0];
366   [layoutManager setUsesScreenFonts:screen_font_p];
368   [layoutManager addTextContainer:textContainer];
369   [textContainer release];
370   [textStorage addLayoutManager:layoutManager];
371   [layoutManager release];
373   if (!(textStorage && layoutManager && textContainer))
374     {
375       [textStorage release];
377       return 0;
378     }
380   stringLength = [string length];
382   /* Force layout.  */
383   (void) [layoutManager glyphRangeForTextContainer:textContainer];
385   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
387   /* Remove the appended trailing space because otherwise it may
388      generate a wrong result for a right-to-left text.  */
389   [textStorage beginEditing];
390   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
391   [textStorage endEditing];
392   (void) [layoutManager glyphRangeForTextContainer:textContainer];
394   i = 0;
395   while (i < stringLength)
396     {
397       NSRange range;
398       NSFont *fontInTextStorage =
399         [textStorage attribute:NSFontAttributeName atIndex:i
400                      longestEffectiveRange:&range
401                        inRange:(NSMakeRange (0, stringLength))];
403       if (!(fontInTextStorage == font
404             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
405         break;
406       i = NSMaxRange (range);
407     }
408   if (i < stringLength)
409     /* Make the test `used <= glyph_len' below fail if textStorage
410        contained some fonts other than the specified one.  */
411     used = glyph_len + 1;
412   else
413     {
414       NSRange range = NSMakeRange (0, stringLength);
416       range = [layoutManager glyphRangeForCharacterRange:range
417                                     actualCharacterRange:NULL];
418       numberOfGlyphs = NSMaxRange (range);
419       used = numberOfGlyphs;
420       for (i = 0; i < numberOfGlyphs; i++)
421         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
422           used--;
423     }
425   if (0 < used && used <= glyph_len)
426     {
427       NSUInteger glyphIndex, prevGlyphIndex;
428       unsigned char bidiLevel;
429       NSUInteger *permutation;
430       NSRange compRange, range;
431       CGFloat totalAdvance;
433       glyphIndex = 0;
434       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
435         glyphIndex++;
437       /* For now we assume the direction is not changed within the
438          string.  */
439       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
440                                glyphs:NULL characterIndexes:NULL
441                     glyphInscriptions:NULL elasticBits:NULL
442                            bidiLevels:&bidiLevel];
443       if (bidiLevel & 1)
444         permutation = xmalloc (sizeof (NSUInteger) * used);
445       else
446         permutation = NULL;
448 #define RIGHT_TO_LEFT_P permutation
450       /* Fill the `comp_range' member of struct mac_glyph_layout, and
451          setup a permutation for right-to-left text.  */
452       compRange = NSMakeRange (0, 0);
453       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
454            range.length++)
455         {
456           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
457           NSUInteger characterIndex =
458             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
460           gl->string_index = characterIndex;
462           if (characterIndex >= NSMaxRange (compRange))
463             {
464               compRange.location = NSMaxRange (compRange);
465               do
466                 {
467                   NSRange characterRange =
468                     [string
469                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
471                   compRange.length =
472                     NSMaxRange (characterRange) - compRange.location;
473                   [layoutManager glyphRangeForCharacterRange:compRange
474                                         actualCharacterRange:&characterRange];
475                   characterIndex = NSMaxRange (characterRange) - 1;
476                 }
477               while (characterIndex >= NSMaxRange (compRange));
479               if (RIGHT_TO_LEFT_P)
480                 for (i = 0; i < range.length; i++)
481                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
483               range = NSMakeRange (NSMaxRange (range), 0);
484             }
486           gl->comp_range.location = compRange.location;
487           gl->comp_range.length = compRange.length;
489           while (++glyphIndex < numberOfGlyphs)
490             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
491               break;
492         }
493       if (RIGHT_TO_LEFT_P)
494         for (i = 0; i < range.length; i++)
495           permutation[range.location + i] = NSMaxRange (range) - i - 1;
497       /* Then fill the remaining members.  */
498       glyphIndex = prevGlyphIndex = 0;
499       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
500         glyphIndex++;
502       if (!RIGHT_TO_LEFT_P)
503         totalAdvance = 0;
504       else
505         {
506           NSUInteger nrects;
507           NSRect *glyphRects =
508             [layoutManager
509               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
510               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
511                      inTextContainer:textContainer rectCount:&nrects];
513           totalAdvance = NSMaxX (glyphRects[0]);
514         }
516       for (i = 0; i < used; i++)
517         {
518           struct mac_glyph_layout *gl;
519           NSPoint location;
520           NSUInteger nextGlyphIndex;
521           NSRange glyphRange;
522           NSRect *glyphRects;
523           NSUInteger nrects;
525           if (!RIGHT_TO_LEFT_P)
526             gl = glyph_layouts + i;
527           else
528             {
529               NSUInteger dest = permutation[i];
531               gl = glyph_layouts + dest;
532               if (i < dest)
533                 {
534                   CFIndex tmp = gl->string_index;
536                   gl->string_index = glyph_layouts[i].string_index;
537                   glyph_layouts[i].string_index = tmp;
538                 }
539             }
540           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
542           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
543           gl->baseline_delta = spaceLocation.y - location.y;
545           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
546                nextGlyphIndex++)
547             if (![layoutManager
548                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
549               break;
551           if (!RIGHT_TO_LEFT_P)
552             {
553               CGFloat maxX;
555               if (prevGlyphIndex == 0)
556                 glyphRange = NSMakeRange (0, nextGlyphIndex);
557               else
558                 glyphRange = NSMakeRange (glyphIndex,
559                                           nextGlyphIndex - glyphIndex);
560               glyphRects =
561                 [layoutManager
562                   rectArrayForGlyphRange:glyphRange
563                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
564                          inTextContainer:textContainer rectCount:&nrects];
565               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
566               gl->advance_delta = location.x - totalAdvance;
567               gl->advance = maxX - totalAdvance;
568               totalAdvance = maxX;
569             }
570           else
571             {
572               CGFloat minX;
574               if (nextGlyphIndex == numberOfGlyphs)
575                 glyphRange = NSMakeRange (prevGlyphIndex,
576                                           numberOfGlyphs - prevGlyphIndex);
577               else
578                 glyphRange = NSMakeRange (prevGlyphIndex,
579                                           glyphIndex + 1 - prevGlyphIndex);
580               glyphRects =
581                 [layoutManager
582                   rectArrayForGlyphRange:glyphRange
583                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
584                          inTextContainer:textContainer rectCount:&nrects];
585               minX = min (NSMinX (glyphRects[0]), totalAdvance);
586               gl->advance = totalAdvance - minX;
587               totalAdvance = minX;
588               gl->advance_delta = location.x - totalAdvance;
589             }
591           prevGlyphIndex = glyphIndex + 1;
592           glyphIndex = nextGlyphIndex;
593         }
595       if (RIGHT_TO_LEFT_P)
596         xfree (permutation);
598 #undef RIGHT_TO_LEFT_P
600       result = used;
601    }
602  [textStorage release];
604   return result;
607 static CFIndex
608 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
609                        struct mac_glyph_layout *glyph_layouts,
610                        CFIndex glyph_len)
612   return mac_font_shape_1 ([(NSFont *)font printerFont],
613                            (NSString *) string,
614                            glyph_layouts, glyph_len, YES);
617 static CGColorRef
618 get_cgcolor(unsigned long idx, struct frame *f)
620   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
621   [nsColor set];
622   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
623   NSInteger noc = [nsColor numberOfComponents];
624   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
625   CGColorRef cgColor;
627   [nsColor getComponents: components];
628   cgColor = CGColorCreate (colorSpace, components);
629   xfree (components);
630   return cgColor;
633 #define CG_SET_FILL_COLOR_WITH_GC_FOREGROUND(context, s)                \
634   do {                                                                  \
635     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (s->face),     \
636                                       s->f);                            \
637     CGContextSetFillColorWithColor (context, refcol_) ;                 \
638     CGColorRelease (refcol_);                                           \
639   } while (0)
640 #define CG_SET_FILL_COLOR_WITH_GC_BACKGROUND(context, s)                \
641   do {                                                                  \
642     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (s->face),\
643                                       s->f);                            \
644     CGContextSetFillColorWithColor (context, refcol_);                  \
645     CGColorRelease (refcol_);                                           \
646   } while (0)
647 #define CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND(context, s)              \
648   do {                                                                  \
649     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (s->face),\
650                                       s->f);                            \
651     CGContextSetStrokeColorWithColor (context, refcol_);                \
652     CGColorRelease (refcol_);                                           \
653   } while (0)
656 /* Mac font driver.  */
658 static struct
660   /* registry name */
661   const char *name;
662   /* characters to distinguish the charset from the others */
663   int uniquifier[6];
664   /* additional constraint by language */
665   CFStringRef lang;
666   /* set on demand */
667   CFCharacterSetRef cf_charset;
668   CFStringRef cf_charset_string;
669 } cf_charset_table[] =
670   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
671     { "iso8859-2", { 0x00A0, 0x010E }},
672     { "iso8859-3", { 0x00A0, 0x0108 }},
673     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
674     { "iso8859-5", { 0x00A0, 0x0401 }},
675     { "iso8859-6", { 0x00A0, 0x060C }},
676     { "iso8859-7", { 0x00A0, 0x0384 }},
677     { "iso8859-8", { 0x00A0, 0x05D0 }},
678     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
679     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
680     { "iso8859-11", { 0x00A0, 0x0E01 }},
681     { "iso8859-13", { 0x00A0, 0x201C }},
682     { "iso8859-14", { 0x00A0, 0x0174 }},
683     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
684     { "iso8859-16", { 0x00A0, 0x0218}},
685     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
686     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
687     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
688     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
689     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
690     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
691     { "cns11643.1992-3", { 0x201A9 }},
692     { "cns11643.1992-4", { 0x20057 }},
693     { "cns11643.1992-5", { 0x20000 }},
694     { "cns11643.1992-6", { 0x20003 }},
695     { "cns11643.1992-7", { 0x20055 }},
696     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
697     { "jisx0212.1990-0", { 0x4E44 }},
698     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
699     { "jisx0213.2000-2", { 0xFA49 }},
700     { "jisx0213.2004-1", { 0x20B9F }},
701     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
702     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
703     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
704     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
705     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
706     { "unicode-sip", { 0x20000 }},
707     { NULL }
708   };
710 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
711 static const struct
713   CFStringRef language;
714   CFStringRef font_names[3];
715 } macfont_language_default_font_names[] = {
716   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
717                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
718                     NULL }},
719   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
720                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
721                     NULL }},
722   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
723                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
724                          NULL }},
725   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
726                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
727                          NULL }},
728   { NULL }
730 #endif
732 static CGFloat macfont_antialias_threshold;
734 static void
735 macfont_update_antialias_threshold (void)
737   int threshold;
738   Boolean valid_p;
740   threshold =
741     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
742                                      kCFPreferencesCurrentApplication,
743                                      &valid_p);
744   if (valid_p)
745     macfont_antialias_threshold = threshold;
748 static inline Lisp_Object
749 macfont_intern_prop_cfstring (CFStringRef cfstring)
751   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
753   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
756 static inline CFIndex
757 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
759   if (c < 0x10000)
760     {
761       unichars[0] = c;
763       return 1;
764     }
765   else
766     {
767       c -= 0x10000;
768       unichars[0] = (c >> 10) + 0xD800;
769       unichars[1] = (c & 0x3FF) + 0xDC00;
771       return 2;
772     }
775 static Boolean
776 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
777                                          FontSymbolicTraits *sym_traits)
779   SInt64 sint64_value;
781   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
782      OS 10.6 when the value is greater than or equal to 1 << 31.  */
783   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
784     {
785       *sym_traits = (FontSymbolicTraits) sint64_value;
787       return true;
788     }
790   return false;
793 static void
794 macfont_store_descriptor_attributes (FontDescriptorRef desc,
795                                      Lisp_Object spec_or_entity)
797   CFStringRef str;
798   CFDictionaryRef dict;
799   CFNumberRef num;
800   CGFloat floatval;
802   str = mac_font_descriptor_copy_attribute (desc,
803                                             MAC_FONT_FAMILY_NAME_ATTRIBUTE);
804   if (str)
805     {
806       ASET (spec_or_entity, FONT_FAMILY_INDEX,
807             macfont_intern_prop_cfstring (str));
808       CFRelease (str);
809     }
810   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
811   if (dict)
812     {
813       struct {
814         enum font_property_index index;
815         CFStringRef trait;
816         CGPoint points[6];
817       } numeric_traits[] =
818           {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
819             {{-0.4, 50},        /* light */
820              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
821              {0, 100},          /* normal */
822              {0.24, 140},       /* (semi-bold + normal) / 2 */
823              {0.4, 200},        /* bold */
824              {CGFLOAT_MAX, CGFLOAT_MAX}}},
825            {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
826             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
827            {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
828             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
829       int i;
831       for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); i++)
832         {
833           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
834           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
835             {
836               CGPoint *point = numeric_traits[i].points;
838               while (point->x < floatval)
839                 point++;
840               if (point == numeric_traits[i].points)
841                 point++;
842               else if (point->x == CGFLOAT_MAX)
843                 point--;
844               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
845                                            * ((point->y - (point - 1)->y)
846                                               / (point->x - (point - 1)->x)));
847               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
848                               make_number (lround (floatval)));
849             }
850         }
852       num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
853       if (num)
854         {
855           FontSymbolicTraits sym_traits;
856           int spacing;
858           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
859           spacing = (sym_traits & MAC_FONT_TRAIT_MONO_SPACE
860                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
861           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
862         }
864       CFRelease (dict);
865     }
866   num = mac_font_descriptor_copy_attribute (desc, MAC_FONT_SIZE_ATTRIBUTE);
867   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
868     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
869   else
870     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
871   if (num)
872     CFRelease (num);
875 static Lisp_Object
876 macfont_descriptor_entity (FontDescriptorRef desc, Lisp_Object extra,
877                            FontSymbolicTraits synth_sym_traits)
879   Lisp_Object entity;
880   CFDictionaryRef dict;
881   FontSymbolicTraits sym_traits = 0;
882   CFStringRef name;
884   entity = font_make_entity ();
886   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
887   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
889   macfont_store_descriptor_attributes (desc, entity);
891   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
892   if (dict)
893     {
894       CFNumberRef num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
896       if (num)
897         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
898       CFRelease (dict);
899     }
900   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
901     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
902   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
903   name = mac_font_descriptor_copy_attribute (desc, MAC_FONT_NAME_ATTRIBUTE);
904   font_put_extra (entity, QCfont_entity,
905                   make_save_ptr_int ((void *) name, sym_traits));
906   if (synth_sym_traits & MAC_FONT_TRAIT_ITALIC)
907     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
908                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
909   if (synth_sym_traits & MAC_FONT_TRAIT_BOLD)
910     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
911                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
912   if (synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
913     ASET (entity, FONT_SPACING_INDEX,
914           make_number (FONT_SPACING_SYNTHETIC_MONO));
916   return entity;
919 static CFStringRef
920 macfont_create_family_with_symbol (Lisp_Object symbol)
922   static CFArrayRef families = NULL;
923   CFStringRef result = NULL, family_name;
924   int using_cache_p = 1;
925   CFComparatorFunction family_name_comparator;
927   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
928   if (family_name == NULL)
929     return NULL;
931 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
932 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
933   if (CTFontManagerCompareFontFamilyNames != NULL)
934 #endif
935     {
936       family_name_comparator = CTFontManagerCompareFontFamilyNames;
937     }
938 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
939   else               /* CTFontManagerCompareFontFamilyNames == NULL */
940 #endif
941 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
942 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
943     {
944       family_name_comparator = mac_font_family_compare;
945     }
946 #endif
948   if ((*family_name_comparator) (family_name, CFSTR ("LastResort"), NULL)
949       == kCFCompareEqualTo)
950     result = CFSTR ("LastResort");
951   else
952     while (1)
953       {
954         CFIndex i, count;
956         if (families == NULL)
957           {
958             families = mac_font_create_available_families ();
959             using_cache_p = 0;
960             if (families == NULL)
961               break;
962           }
964         count = CFArrayGetCount (families);
965         i = CFArrayBSearchValues (families, CFRangeMake (0, count),
966                                   (const void *) family_name,
967                                   family_name_comparator, NULL);
968         if (i < count)
969           {
970             CFStringRef name = CFArrayGetValueAtIndex (families, i);
972             if ((*family_name_comparator) (name, family_name, NULL)
973                 == kCFCompareEqualTo)
974               result = CFRetain (name);
975           }
977         if (result || !using_cache_p)
978           break;
979         else
980           {
981             CFRelease (families);
982             families = NULL;
983           }
984       }
986   CFRelease (family_name);
988   return result;
991 #define WIDTH_FRAC_BITS         (4)
992 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
994 struct macfont_metrics
996   unsigned char lbearing_low, rbearing_low;
997   signed lbearing_high : 4, rbearing_high : 4;
998   unsigned char ascent_low, descent_low;
999   signed ascent_high : 4, descent_high : 4;
1001   /* These two members are used for fixed-point representation of
1002      glyph width.  The `width_int' member is an integer that is
1003      closest to the width.  The `width_frac' member is the fractional
1004      adjustment representing a value in [-.5, .5], multiplied by
1005      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1006      the advance delta for centering instead of the glyph width.  */
1007   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1010 #define METRICS_VALUE(metrics, member) \
1011   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1012 #define METRICS_SET_VALUE(metrics, member, value) \
1013   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff; \
1014       (metrics)->member##_high = tmp >> 8;} while (0)
1016 enum metrics_status
1017   {
1018     METRICS_INVALID = -1,    /* metrics entry is invalid */
1019     METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1020   };
1022 #define METRICS_STATUS(metrics) \
1023   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1024 #define METRICS_SET_STATUS(metrics, status) \
1025   do {METRICS_SET_VALUE (metrics, ascent, 0); \
1026       METRICS_SET_VALUE (metrics, descent, status);} while (0)
1028 #define METRICS_NCOLS_PER_ROW   (128)
1029 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1030 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1032 static int
1033 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1034                        struct font_metrics *metrics, CGFloat *advance_delta,
1035                        int force_integral_p)
1037   struct macfont_info *macfont_info = (struct macfont_info *) font;
1038   FontRef macfont = macfont_info->macfont;
1039   int row, col;
1040   struct macfont_metrics *cache;
1041   int width;
1043   row = glyph / METRICS_NCOLS_PER_ROW;
1044   col = glyph % METRICS_NCOLS_PER_ROW;
1045   if (row >= macfont_info->metrics_nrows)
1046     {
1047       macfont_info->metrics =
1048         xrealloc (macfont_info->metrics,
1049                   sizeof (struct macfont_metrics *) * (row + 1));
1050       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1051               (sizeof (struct macfont_metrics *)
1052                * (row + 1 - macfont_info->metrics_nrows)));
1053       macfont_info->metrics_nrows = row + 1;
1054     }
1055   if (macfont_info->metrics[row] == NULL)
1056     {
1057       struct macfont_metrics *new;
1058       int i;
1060       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1061       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1062         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1063       macfont_info->metrics[row] = new;
1064     }
1065   cache = macfont_info->metrics[row] + col;
1067   if (METRICS_STATUS (cache) == METRICS_INVALID)
1068     {
1069       CGFloat fwidth;
1071       if (macfont_info->screen_font)
1072         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1073       else
1074         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1076       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1077          advance delta value.  */
1078       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1079         fwidth = (font->pixel_size - fwidth) / 2;
1080       cache->width_int = lround (fwidth);
1081       cache->width_frac = lround ((fwidth - cache->width_int)
1082                                   * WIDTH_FRAC_SCALE);
1083       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1084     }
1085   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1086     width = font->pixel_size;
1087   else
1088     width = cache->width_int;
1090   if (metrics)
1091     {
1092       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1093         {
1094           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1096           if (macfont_info->synthetic_italic_p)
1097             {
1098               /* We assume the members a, b, c, and d in
1099                  synthetic_italic_atfm are non-negative.  */
1100               bounds.origin =
1101                 CGPointApplyAffineTransform (bounds.origin,
1102                                              synthetic_italic_atfm);
1103               bounds.size =
1104                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1105             }
1106           if (macfont_info->synthetic_bold_p)
1107             {
1108               CGFloat d =
1109                 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1111               bounds = CGRectInset (bounds, d, d);
1112             }
1113           switch (macfont_info->spacing)
1114             {
1115             case MACFONT_SPACING_PROPORTIONAL:
1116               bounds.origin.x += - (cache->width_frac
1117                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1118               break;
1119             case MACFONT_SPACING_MONO:
1120               break;
1121             case MACFONT_SPACING_SYNTHETIC_MONO:
1122               bounds.origin.x += (cache->width_int
1123                                   + (cache->width_frac
1124                                      / (CGFloat) WIDTH_FRAC_SCALE));
1125               break;
1126             }
1127           if (bounds.size.width > 0)
1128             {
1129               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1130               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1131                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1132             }
1133           bounds = CGRectIntegral (bounds);
1134           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1135           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1136           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1137           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1138         }
1139       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1140       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1141       metrics->width = width;
1142       metrics->ascent = METRICS_VALUE (cache, ascent);
1143       metrics->descent = METRICS_VALUE (cache, descent);
1144     }
1146   if (advance_delta)
1147     {
1148       switch (macfont_info->spacing)
1149         {
1150         case MACFONT_SPACING_PROPORTIONAL:
1151           *advance_delta = (force_integral_p ? 0
1152                             : - (cache->width_frac
1153                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1154           break;
1155         case MACFONT_SPACING_MONO:
1156           *advance_delta = 0;
1157           break;
1158         case MACFONT_SPACING_SYNTHETIC_MONO:
1159           *advance_delta = (force_integral_p ? cache->width_int
1160                             : (cache->width_int
1161                                + (cache->width_frac
1162                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1163           break;
1164         }
1165     }
1167   return width;
1170 static CFMutableDictionaryRef macfont_cache_dictionary;
1172 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1173    equal to the number of rows that are invalid as BMP (i.e., from
1174    U+D800 to U+DFFF).  */
1175 #define ROW_PERM_OFFSET (8)
1177 /* The number of glyphs that can be stored in a value for a single
1178    entry of CFDictionary.  */
1179 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1181 struct macfont_cache
1183   int reference_count;
1184   CFCharacterSetRef cf_charset;
1185   struct {
1186     /* The cached glyph for a BMP character c is stored in
1187        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1188        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1189     unsigned char row_nkeys_or_perm[256];
1190     CGGlyph **matrix;
1192     /* Number of rows for which the BMP cache is allocated so far.
1193        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1194     int nrows;
1196     /* The cached glyph for a character c is stored as the (c %
1197        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1198        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1199        not stored here if row_nkeys_or_perm[c / 256] >=
1200        ROW_PERM_OFFSET.  */
1201     CFMutableDictionaryRef dictionary;
1202   } glyph;
1204   struct {
1205     /* UVS (Unicode Variation Sequence) subtable data, which is of
1206        type CFDataRef if available.  NULL means it is not initialized
1207        yet.  kCFNull means the subtable is not found and there is no
1208        suitable fallback table for this font.  */
1209     CFTypeRef table;
1211     /* Character collection specifying the destination of the mapping
1212        provided by `table' above.  If `table' is obtained from the UVS
1213        subtable in the font cmap table, then the value of this member
1214        should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING.  */
1215     CharacterCollection collection;
1216   } uvs;
1219 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1220 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1221 static void macfont_release_cache (struct macfont_cache *);
1222 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1223 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1224 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1225 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1226                                           CharacterCollection, CGFontIndex);
1227 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1229 static struct macfont_cache *
1230 macfont_lookup_cache (CFStringRef key)
1232   struct macfont_cache *cache;
1234   if (macfont_cache_dictionary == NULL)
1235     {
1236       macfont_cache_dictionary =
1237         CFDictionaryCreateMutable (NULL, 0,
1238                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1239       cache = NULL;
1240     }
1241   else
1242     cache = ((struct macfont_cache *)
1243              CFDictionaryGetValue (macfont_cache_dictionary, key));
1245   if (cache == NULL)
1246     {
1247       FontRef macfont = mac_font_create_with_name (key, 0);
1249       if (macfont)
1250         {
1251           cache = xzalloc (sizeof (struct macfont_cache));
1252           /* Treat the LastResort font as if it contained glyphs for
1253              all characters.  This may look too rough, but neither
1254              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1255              for this font is correct for non-BMP characters on Mac OS
1256              X 10.5, anyway.  */
1257           if (CFStringCompare (key, CFSTR ("LastResort"), 0)
1258               == kCFCompareEqualTo)
1259             {
1260               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1262               cache->cf_charset =
1263                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1264             }
1265           if (cache->cf_charset == NULL)
1266             cache->cf_charset = mac_font_copy_character_set (macfont);
1267           CFDictionaryAddValue (macfont_cache_dictionary, key,
1268                                 (const void *) cache);
1269           CFRelease (macfont);
1270         }
1271     }
1273   return cache;
1276 static struct macfont_cache *
1277 macfont_retain_cache (struct macfont_cache *cache)
1279   cache->reference_count++;
1281   return cache;
1284 static void
1285 macfont_release_cache (struct macfont_cache *cache)
1287   if (--cache->reference_count == 0)
1288     {
1289       int i;
1291       for (i = 0; i < cache->glyph.nrows; i++)
1292         xfree (cache->glyph.matrix[i]);
1293       xfree (cache->glyph.matrix);
1294       if (cache->glyph.dictionary)
1295         CFRelease (cache->glyph.dictionary);
1296       memset (&cache->glyph, 0, sizeof (cache->glyph));
1297       if (cache->uvs.table)
1298         CFRelease (cache->uvs.table);
1299       memset (&cache->uvs, 0, sizeof (cache->uvs));
1300     }
1303 static CFCharacterSetRef
1304 macfont_get_cf_charset (struct font *font)
1306   struct macfont_info *macfont_info = (struct macfont_info *) font;
1308   return macfont_info->cache->cf_charset;
1311 static CFCharacterSetRef
1312 macfont_get_cf_charset_for_name (CFStringRef name)
1314   struct macfont_cache *cache = macfont_lookup_cache (name);
1316   return cache->cf_charset;
1319 static CGGlyph
1320 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1322   struct macfont_info *macfont_info = (struct macfont_info *) font;
1323   FontRef macfont = macfont_info->macfont;
1324   struct macfont_cache *cache = macfont_info->cache;
1326   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1327     {
1328       int row = c / 256;
1329       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1331       if (nkeys_or_perm < ROW_PERM_OFFSET)
1332         {
1333           UniChar unichars[256], ch;
1334           CGGlyph *glyphs;
1335           int i, len;
1336           int nrows;
1337 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1338           dispatch_queue_t queue;
1339           dispatch_group_t group = NULL;
1340 #else
1341           int nkeys;
1342 #endif
1344           if (row != 0)
1345             {
1346               CFMutableDictionaryRef dictionary;
1347               uintptr_t key, value;
1348               int nshifts;
1349               CGGlyph glyph;
1351               if (cache->glyph.dictionary == NULL)
1352                 cache->glyph.dictionary =
1353                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1354               dictionary = cache->glyph.dictionary;
1355               key = c / NGLYPHS_IN_VALUE;
1356               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1357               value = ((uintptr_t)
1358                        CFDictionaryGetValue (dictionary, (const void *) key));
1359               glyph = (value >> nshifts);
1360               if (glyph)
1361                 return glyph;
1363               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1364                 {
1365                   ch = c;
1366                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1367                                                            &glyph, 1)
1368                       || glyph == 0)
1369                     glyph = kCGFontIndexInvalid;
1371                   if (value == 0)
1372                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1373                   value |= ((uintptr_t) glyph << nshifts);
1374                   CFDictionarySetValue (dictionary, (const void *) key,
1375                                         (const void *) value);
1377                   return glyph;
1378                 }
1380 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1381               queue =
1382                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1383               group = dispatch_group_create ();
1384               dispatch_group_async (group, queue, ^{
1385                   int nkeys;
1386                   uintptr_t key;
1387 #endif
1388                   nkeys = nkeys_or_perm;
1389                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1390                     if (CFDictionaryContainsKey (dictionary,
1391                                                  (const void *) key))
1392                       {
1393                         CFDictionaryRemoveValue (dictionary,
1394                                                  (const void *) key);
1395                         if (--nkeys == 0)
1396                           break;
1397                       }
1398 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1399                 });
1400 #endif
1401             }
1403           len = 0;
1404           for (i = 0; i < 256; i++)
1405             {
1406               ch = row * 256 + i;
1407               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1408                 unichars[len++] = ch;
1409             }
1411           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1412           if (len > 0)
1413             {
1414               mac_font_get_glyphs_for_characters (macfont, unichars,
1415                                                   glyphs, len);
1416               while (i > len)
1417                 {
1418                   int next = unichars[len - 1] % 256;
1420                   while (--i > next)
1421                     glyphs[i] = kCGFontIndexInvalid;
1423                   len--;
1424                   glyphs[i] = glyphs[len];
1425                   if (len == 0)
1426                     break;
1427                 }
1428             }
1429           if (i > len)
1430             while (i-- > 0)
1431               glyphs[i] = kCGFontIndexInvalid;
1433           nrows = cache->glyph.nrows;
1434           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1435           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1436           nrows++;
1437           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1438                                           sizeof (CGGlyph *) * nrows);
1439           cache->glyph.matrix[nrows - 1] = glyphs;
1440           cache->glyph.nrows = nrows;
1442 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1443           if (group)
1444             {
1445               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1446               dispatch_release (group);
1447             }
1448 #endif
1449         }
1451       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1452     }
1453   else
1454     {
1455       uintptr_t key, value;
1456       int nshifts;
1457       CGGlyph glyph;
1459       if (cache->glyph.dictionary == NULL)
1460         cache->glyph.dictionary =
1461           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1462       key = c / NGLYPHS_IN_VALUE;
1463       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1464       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1465                                                 (const void *) key);
1466       glyph = (value >> nshifts);
1467       if (glyph == 0)
1468         {
1469           UniChar unichars[2];
1470           CGGlyph glyphs[2];
1471           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1473           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1474                                                   count))
1475             glyph = glyphs[0];
1476           if (glyph == 0)
1477             glyph = kCGFontIndexInvalid;
1479           value |= ((uintptr_t) glyph << nshifts);
1480           CFDictionarySetValue (cache->glyph.dictionary,
1481                                 (const void *) key, (const void *) value);
1482         }
1484       return glyph;
1485     }
1488 static CGGlyph
1489 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1490                            CGFontIndex cid)
1492   struct macfont_info *macfont_info = (struct macfont_info *) font;
1493   FontRef macfont = macfont_info->macfont;
1495   /* Cache it? */
1496   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1499 static CFDataRef
1500 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1502   struct macfont_info *macfont_info = (struct macfont_info *) font;
1503   FontRef macfont = macfont_info->macfont;
1504   struct macfont_cache *cache = macfont_info->cache;
1505   CFDataRef result = NULL;
1507   if (cache->uvs.table == NULL)
1508     {
1509       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1510       CharacterCollection uvs_collection =
1511         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1513       if (uvs_table == NULL
1514           && mac_font_get_glyph_for_cid (macfont,
1515                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1516                                          6480) != kCGFontIndexInvalid)
1517         {
1518           /* If the glyph for U+4E55 is accessible via its CID 6480,
1519              then we use the Adobe-Japan1 UVS table, which maps a
1520              variation sequence to a CID, as a fallback.  */
1521           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1523           if (mac_uvs_table_adobe_japan1 == NULL)
1524             mac_uvs_table_adobe_japan1 =
1525               CFDataCreateWithBytesNoCopy (NULL,
1526                                            mac_uvs_table_adobe_japan1_bytes,
1527                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1528                                            kCFAllocatorNull);
1529           if (mac_uvs_table_adobe_japan1)
1530             {
1531               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1532               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1533             }
1534         }
1535       if (uvs_table == NULL)
1536         cache->uvs.table = kCFNull;
1537       else
1538         cache->uvs.table = uvs_table;
1539       cache->uvs.collection = uvs_collection;
1540     }
1542   if (cache->uvs.table != kCFNull)
1543     {
1544       result = cache->uvs.table;
1545       *collection = cache->uvs.collection;
1546     }
1548   return result;
1551 static Lisp_Object macfont_get_cache (struct frame *);
1552 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1553 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1554 static Lisp_Object macfont_list_family (struct frame *);
1555 static void macfont_free_entity (Lisp_Object);
1556 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1557 static void macfont_close (struct font *);
1558 static int macfont_has_char (Lisp_Object, int);
1559 static unsigned macfont_encode_char (struct font *, int);
1560 static int macfont_text_extents (struct font *, unsigned int *, int,
1561                                  struct font_metrics *);
1562 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1563 static Lisp_Object macfont_shape (Lisp_Object);
1564 static int macfont_variation_glyphs (struct font *, int c,
1565                                      unsigned variations[256]);
1566 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1568 static struct font_driver macfont_driver =
1569   {
1570     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1571     0,                          /* case insensitive */
1572     macfont_get_cache,
1573     macfont_list,
1574     macfont_match,
1575     macfont_list_family,
1576     macfont_free_entity,
1577     macfont_open,
1578     macfont_close,
1579     NULL,                       /* prepare_face */
1580     NULL,                       /* done_face */
1581     macfont_has_char,
1582     macfont_encode_char,
1583     macfont_text_extents,
1584     macfont_draw,
1585     NULL,                       /* get_bitmap */
1586     NULL,                       /* free_bitmap */
1587     NULL,                       /* get_outline */
1588     NULL,                       /* free_outline */
1589     NULL,                       /* anchor_point */
1590     NULL,                       /* otf_capability */
1591     NULL,                       /* otf_drive */
1592     NULL,                       /* start_for_frame */
1593     NULL,                       /* end_for_frame */
1594     macfont_shape,
1595     NULL,                       /* check */
1596     macfont_variation_glyphs,
1597     macfont_filter_properties,
1598   };
1600 static Lisp_Object
1601 macfont_get_cache (struct frame * f)
1603   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1605   return (dpyinfo->name_list_element);
1608 static int
1609 macfont_get_charset (Lisp_Object registry)
1611   char *str = SSDATA (SYMBOL_NAME (registry));
1612   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1613   Lisp_Object regexp;
1614   int i, j;
1616   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1617     {
1618       if (str[i] == '.')
1619         re[j++] = '\\';
1620       else if (str[i] == '*')
1621         re[j++] = '.';
1622       re[j] = str[i];
1623       if (re[j] == '?')
1624         re[j] = '.';
1625     }
1626   re[j] = '\0';
1627   regexp = make_unibyte_string (re, j);
1628   for (i = 0; cf_charset_table[i].name; i++)
1629     if (fast_c_string_match_ignore_case
1630         (regexp, cf_charset_table[i].name,
1631          strlen (cf_charset_table[i].name)) >= 0)
1632       break;
1633   if (! cf_charset_table[i].name)
1634     return -1;
1635   if (! cf_charset_table[i].cf_charset)
1636     {
1637       int *uniquifier = cf_charset_table[i].uniquifier;
1638       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1639       CFIndex count = 0;
1640       CFStringRef string;
1641       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1643       if (! charset)
1644         return -1;
1645       for (j = 0; uniquifier[j]; j++)
1646         {
1647           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1648                                                         unichars + count);
1649           CFCharacterSetAddCharactersInRange (charset,
1650                                               CFRangeMake (uniquifier[j], 1));
1651         }
1653       string = CFStringCreateWithCharacters (NULL, unichars, count);
1654       if (! string)
1655         {
1656           CFRelease (charset);
1657           return -1;
1658         }
1659       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1660                                                                  charset);
1661       CFRelease (charset);
1662       /* CFCharacterSetCreateWithCharactersInString does not handle
1663          surrogate pairs properly as of Mac OS X 10.5.  */
1664      cf_charset_table[i].cf_charset_string = string;
1665     }
1666   return i;
1669 struct OpenTypeSpec
1671   Lisp_Object script;
1672   unsigned int script_tag, langsys_tag;
1673   int nfeatures[2];
1674   unsigned int *features[2];
1677 #define OTF_SYM_TAG(SYM, TAG)                                   \
1678   do {                                                          \
1679     unsigned char *p = SDATA (SYMBOL_NAME (SYM));               \
1680     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1681   } while (0)
1683 #define OTF_TAG_STR(TAG, P)                     \
1684   do {                                          \
1685     (P)[0] = (char) (TAG >> 24);                \
1686     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1687     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1688     (P)[3] = (char) (TAG & 0xFF);               \
1689     (P)[4] = '\0';                              \
1690   } while (0)
1692 static struct OpenTypeSpec *
1693 macfont_get_open_type_spec (Lisp_Object otf_spec)
1695   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1696   Lisp_Object val;
1697   int i, j;
1698   bool negative;
1700   if (! spec)
1701     return NULL;
1702   spec->script = XCAR (otf_spec);
1703   if (! NILP (spec->script))
1704     {
1705       OTF_SYM_TAG (spec->script, spec->script_tag);
1706       val = assq_no_quit (spec->script, Votf_script_alist);
1707       if (CONSP (val) && SYMBOLP (XCDR (val)))
1708         spec->script = XCDR (val);
1709       else
1710         spec->script = Qnil;
1711     }
1712   else
1713     spec->script_tag = 0x44464C54;      /* "DFLT" */
1714   otf_spec = XCDR (otf_spec);
1715   spec->langsys_tag = 0;
1716   if (! NILP (otf_spec))
1717     {
1718       val = XCAR (otf_spec);
1719       if (! NILP (val))
1720         OTF_SYM_TAG (val, spec->langsys_tag);
1721       otf_spec = XCDR (otf_spec);
1722     }
1723   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1724   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1725     {
1726       Lisp_Object len;
1728       val = XCAR (otf_spec);
1729       if (NILP (val))
1730         continue;
1731       len = Flength (val);
1732       spec->features[i] =
1733         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1734          ? 0
1735          : malloc (XINT (len) * sizeof *spec->features[i]));
1736       if (! spec->features[i])
1737         {
1738           if (i > 0 && spec->features[0])
1739             free (spec->features[0]);
1740           free (spec);
1741           return NULL;
1742         }
1743       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1744         {
1745           if (NILP (XCAR (val)))
1746             negative = 1;
1747           else
1748             {
1749               unsigned int tag;
1751               OTF_SYM_TAG (XCAR (val), tag);
1752               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1753             }
1754         }
1755       spec->nfeatures[i] = j;
1756     }
1757   return spec;
1760 static CFMutableDictionaryRef
1761 macfont_create_attributes_with_spec (Lisp_Object spec)
1763   Lisp_Object tmp, extra;
1764   CFMutableArrayRef langarray = NULL;
1765   CFCharacterSetRef charset = NULL;
1766   CFStringRef charset_string = NULL;
1767   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1768   Lisp_Object script = Qnil;
1769   Lisp_Object registry;
1770   int cf_charset_idx, i;
1771   struct OpenTypeSpec *otspec = NULL;
1772   struct {
1773     enum font_property_index index;
1774     CFStringRef trait;
1775     CGPoint points[6];
1776   } numeric_traits[] =
1777       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1778         {{-0.4, 50},            /* light */
1779          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1780          {0, 100},              /* normal */
1781          {0.24, 140},           /* (semi-bold + normal) / 2 */
1782          {0.4, 200},            /* bold */
1783          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1784        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1785         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1786        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1787         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1789   registry = AREF (spec, FONT_REGISTRY_INDEX);
1790   if (NILP (registry)
1791       || EQ (registry, Qascii_0)
1792       || EQ (registry, Qiso10646_1)
1793       || EQ (registry, Qunicode_bmp))
1794     cf_charset_idx = -1;
1795   else
1796     {
1797       CFStringRef lang;
1799       cf_charset_idx = macfont_get_charset (registry);
1800       if (cf_charset_idx < 0)
1801         goto err;
1802       charset = cf_charset_table[cf_charset_idx].cf_charset;
1803       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1804       lang = cf_charset_table[cf_charset_idx].lang;
1805       if (lang)
1806         {
1807           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1808           if (! langarray)
1809             goto err;
1810           CFArrayAppendValue (langarray, lang);
1811         }
1812     }
1814   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1815        CONSP (extra); extra = XCDR (extra))
1816     {
1817       Lisp_Object key, val;
1819       tmp = XCAR (extra);
1820       key = XCAR (tmp), val = XCDR (tmp);
1821       if (EQ (key, QClang))
1822         {
1823           if (! langarray)
1824             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1825           if (! langarray)
1826             goto err;
1827           if (SYMBOLP (val))
1828             val = list1 (val);
1829           for (; CONSP (val); val = XCDR (val))
1830             if (SYMBOLP (XCAR (val)))
1831               {
1832                 CFStringRef lang =
1833                   cfstring_create_with_string_noencode (SYMBOL_NAME
1834                                                         (XCAR (val)));
1836                 if (lang == NULL)
1837                   goto err;
1838                 CFArrayAppendValue (langarray, lang);
1839                 CFRelease (lang);
1840               }
1841         }
1842       else if (EQ (key, QCotf))
1843         {
1844           otspec = macfont_get_open_type_spec (val);
1845           if (! otspec)
1846             goto err;
1847           script = otspec->script;
1848         }
1849       else if (EQ (key, QCscript))
1850         script = val;
1851     }
1853   if (! NILP (script) && ! charset)
1854     {
1855       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1857       if (CONSP (chars) && CONSP (CDR (chars)))
1858         {
1859           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1860           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1862           if (! string || !cs)
1863             {
1864               if (string)
1865                 CFRelease (string);
1866               else if (cs)
1867                 CFRelease (cs);
1868               goto err;
1869             }
1870           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1871             if (CHARACTERP (XCAR (chars)))
1872               {
1873                 UniChar unichars[2];
1874                 CFIndex count =
1875                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1876                                                        unichars);
1877                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1879                 CFStringAppendCharacters (string, unichars, count);
1880                 CFCharacterSetAddCharactersInRange (cs, range);
1881               }
1882           charset = cs;
1883           /* CFCharacterSetCreateWithCharactersInString does not
1884              handle surrogate pairs properly as of Mac OS X 10.5.  */
1885           charset_string = string;
1886         }
1887     }
1889   attributes = CFDictionaryCreateMutable (NULL, 0,
1890                                           &kCFTypeDictionaryKeyCallBacks,
1891                                           &kCFTypeDictionaryValueCallBacks);
1892   if (! attributes)
1893     goto err;
1895   tmp = AREF (spec, FONT_FAMILY_INDEX);
1896   if (SYMBOLP (tmp) && ! NILP (tmp))
1897     {
1898       CFStringRef family = macfont_create_family_with_symbol (tmp);
1900       if (! family)
1901         goto err;
1902       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1903                             family);
1904       CFRelease (family);
1905     }
1907   traits = CFDictionaryCreateMutable (NULL, 4,
1908                                       &kCFTypeDictionaryKeyCallBacks,
1909                                       &kCFTypeDictionaryValueCallBacks);
1910   if (! traits)
1911     goto err;
1913   for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); i++)
1914     {
1915       tmp = AREF (spec, numeric_traits[i].index);
1916       if (INTEGERP (tmp))
1917         {
1918           CGPoint *point = numeric_traits[i].points;
1919           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1920           CFNumberRef num;
1922           while (point->y < floatval)
1923             point++;
1924           if (point == numeric_traits[i].points)
1925             point++;
1926           else if (point->y == CGFLOAT_MAX)
1927             point--;
1928           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1929                                        * ((point->x - (point - 1)->x)
1930                                           / (point->y - (point - 1)->y)));
1931           if (floatval > 1.0)
1932             floatval = 1.0;
1933           else if (floatval < -1.0)
1934             floatval = -1.0;
1935           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1936           if (! num)
1937             goto err;
1938           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1939           CFRelease (num);
1940         }
1941     }
1942   if (CFDictionaryGetCount (traits))
1943     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1945   if (charset)
1946     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1947                           charset);
1948   if (charset_string)
1949     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1950                           charset_string);
1951   if (langarray)
1952     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1954   goto finish;
1956  err:
1957   if (attributes)
1958     {
1959       CFRelease (attributes);
1960       attributes = NULL;
1961     }
1963  finish:
1964   if (langarray) CFRelease (langarray);
1965   if (charset && cf_charset_idx < 0) CFRelease (charset);
1966   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1967   if (traits) CFRelease (traits);
1968   if (otspec)
1969     {
1970       if (otspec->nfeatures[0] > 0)
1971         free (otspec->features[0]);
1972       if (otspec->nfeatures[1] > 0)
1973         free (otspec->features[1]);
1974       free (otspec);
1975     }
1977   return attributes;
1980 static Boolean
1981 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1982                                           CFCharacterSetRef charset,
1983                                           Lisp_Object chars,
1984                                           CFArrayRef languages)
1986   Boolean result = true;
1988   if (charset || VECTORP (chars))
1989     {
1990       CFCharacterSetRef desc_charset =
1991         mac_font_descriptor_copy_attribute (desc,
1992                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1994       if (desc_charset == NULL)
1995         result = false;
1996       else
1997         {
1998           if (charset)
1999             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2000           else                  /* VECTORP (chars) */
2001             {
2002               ptrdiff_t j;
2004               for (j = 0; j < ASIZE (chars); j++)
2005                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2006                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2007                                                             XFASTINT (AREF (chars, j))))
2008                   break;
2009               if (j == ASIZE (chars))
2010                 result = false;
2011             }
2012           CFRelease (desc_charset);
2013         }
2014     }
2015   if (result && languages)
2016     result = mac_font_descriptor_supports_languages (desc, languages);
2018   return result;
2021 static CFIndex
2022 macfont_closest_traits_index (CFArrayRef traits_array,
2023                               FontSymbolicTraits target)
2025   CFIndex i, result = -1, count = CFArrayGetCount (traits_array);
2026   int min_distance = (1 << 3);
2028   for (i = 0; i < count; i++)
2029     {
2030       FontSymbolicTraits traits, diff;
2031       int distance = 0;
2033       traits = ((FontSymbolicTraits) (uintptr_t)
2034                 CFArrayGetValueAtIndex (traits_array, i));
2035       diff = (target ^ traits);
2036       /* We prefer synthetic bold of italic to synthetic italic of
2037          bold when both bold and italic are available but bold-italic
2038          is not available.  */
2039       if (diff & MAC_FONT_TRAIT_BOLD)
2040         distance |= (1 << 0);
2041       if (diff & MAC_FONT_TRAIT_ITALIC)
2042         distance |= (1 << 1);
2043       if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2044         distance |= (1 << 2);
2045       if (distance < min_distance)
2046         {
2047           min_distance = distance;
2048           result = i;
2049         }
2050     }
2052   return result;
2055 static Lisp_Object
2056 macfont_list (struct frame *f, Lisp_Object spec)
2058   Lisp_Object val = Qnil, family, extra;
2059   int i, n;
2060   CFStringRef family_name = NULL;
2061   CFMutableDictionaryRef attributes = NULL, traits;
2062   Lisp_Object chars = Qnil;
2063   int spacing = -1;
2064   FontSymbolicTraits synth_sym_traits = 0;
2065   CFArrayRef families;
2066   CFIndex families_count;
2067   CFCharacterSetRef charset = NULL;
2068   CFArrayRef languages = NULL;
2070   block_input ();
2072   family = AREF (spec, FONT_FAMILY_INDEX);
2073   if (! NILP (family))
2074     {
2075       family_name = macfont_create_family_with_symbol (family);
2076       if (family_name == NULL)
2077         goto finish;
2078     }
2080   attributes = macfont_create_attributes_with_spec (spec);
2081   if (! attributes)
2082     goto finish;
2084   languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2086   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2087     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2089   traits = ((CFMutableDictionaryRef)
2090             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2092   n = FONT_SLANT_NUMERIC (spec);
2093   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2094     {
2095       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2096       if (traits)
2097         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2098     }
2100   n = FONT_WEIGHT_NUMERIC (spec);
2101   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2102     {
2103       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2104       if (traits)
2105         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2106     }
2108   if (languages
2109       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2110     {
2111       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2113       if (CFStringHasPrefix (language, CFSTR ("ja"))
2114           || CFStringHasPrefix (language, CFSTR ("ko"))
2115           || CFStringHasPrefix (language, CFSTR ("zh")))
2116         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2117     }
2119   /* Create array of families.  */
2120   if (family_name)
2121     families = CFArrayCreate (NULL, (const void **) &family_name,
2122                               1, &kCFTypeArrayCallBacks);
2123   else
2124     {
2125       CFStringRef pref_family;
2126       CFIndex families_count, pref_family_index = -1;
2128       families = mac_font_create_available_families ();
2129       if (families == NULL)
2130         goto err;
2132       families_count = CFArrayGetCount (families);
2134       /* Move preferred family to the front if exists.  */
2135       pref_family =
2136         mac_font_create_preferred_family_for_attributes (attributes);
2137       if (pref_family)
2138         {
2139           pref_family_index =
2140             CFArrayGetFirstIndexOfValue (families,
2141                                          CFRangeMake (0, families_count),
2142                                          pref_family);
2143           CFRelease (pref_family);
2144         }
2145       if (pref_family_index > 0)
2146         {
2147           CFMutableArrayRef mutable_families =
2148             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2150           if (mutable_families)
2151             {
2152               CFArrayAppendValue (mutable_families,
2153                                   CFArrayGetValueAtIndex (families,
2154                                                           pref_family_index));
2155               CFArrayAppendArray (mutable_families, families,
2156                                   CFRangeMake (0, pref_family_index));
2157               if (pref_family_index + 1 < families_count)
2158                 CFArrayAppendArray (mutable_families, families,
2159                                     CFRangeMake (pref_family_index + 1,
2160                                                  families_count
2161                                                  - (pref_family_index + 1)));
2162               CFRelease (families);
2163               families = mutable_families;
2164             }
2165         }
2166     }
2168   charset = CFDictionaryGetValue (attributes,
2169                                   MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2170   if (charset)
2171     {
2172       CFRetain (charset);
2173       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2174     }
2175   else
2176     {
2177       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2178       if (! NILP (val))
2179         {
2180           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2181           if (CONSP (val) && VECTORP (XCDR (val)))
2182             chars = XCDR (val);
2183         }
2184       val = Qnil;
2185     }
2187   if (languages)
2188     {
2189       CFRetain (languages);
2190       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2191     }
2193   val = Qnil;
2194   extra = AREF (spec, FONT_EXTRA_INDEX);
2195   families_count = CFArrayGetCount (families);
2196   for (i = 0; i < families_count; i++)
2197     {
2198       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2199       FontDescriptorRef pat_desc;
2200       CFArrayRef descs;
2201       CFIndex descs_count;
2202       CFMutableArrayRef filtered_descs, traits_array;
2203       Lisp_Object entity;
2204       int j;
2206       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2207                             family_name);
2208       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2209       if (! pat_desc)
2210         goto err;
2212       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2213          10.7 returns NULL if pat_desc represents the LastResort font.
2214          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2215          trailing "s") for such a font.  */
2216       if (CFStringCompare (family_name, CFSTR ("LastResort"), 0)
2217           != kCFCompareEqualTo)
2218         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2219                                                                       NULL);
2220       else
2221         {
2222           FontDescriptorRef lr_desc =
2223             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2224                                                                  NULL);
2225           if (lr_desc)
2226             {
2227               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2228                                      &kCFTypeArrayCallBacks);
2229               CFRelease (lr_desc);
2230             }
2231           else
2232             descs = NULL;
2233         }
2234       CFRelease (pat_desc);
2235       if (! descs)
2236         goto err;
2238       descs_count = CFArrayGetCount (descs);
2239       if (descs_count == 0
2240           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2241                                                         charset, chars,
2242                                                         languages))
2243         {
2244           CFRelease (descs);
2245           continue;
2246         }
2248       filtered_descs =
2249         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2250       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2251       for (j = 0; j < descs_count; j++)
2252         {
2253           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2254           CFDictionaryRef dict;
2255           CFNumberRef num;
2256           FontSymbolicTraits sym_traits;
2258           dict = mac_font_descriptor_copy_attribute (desc,
2259                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2260           if (dict == NULL)
2261             continue;
2263           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2264           CFRelease (dict);
2265           if (num == NULL
2266               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2267             continue;
2269           if (spacing >= 0
2270               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2271               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2272                   != (spacing >= FONT_SPACING_MONO)))
2273             continue;
2275           /* Don't use a color bitmap font unless its family is
2276              explicitly specified.  */
2277           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2278             continue;
2280           if (j > 0
2281               && !macfont_supports_charset_and_languages_p (desc, charset,
2282                                                             chars, languages))
2283             continue;
2285           CFArrayAppendValue (filtered_descs, desc);
2286           CFArrayAppendValue (traits_array,
2287                               (const void *) (uintptr_t) sym_traits);
2288         }
2290       CFRelease (descs);
2291       descs = filtered_descs;
2292       descs_count = CFArrayGetCount (descs);
2294       for (j = 0; j < descs_count; j++)
2295         {
2296           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2297           FontSymbolicTraits sym_traits =
2298             ((FontSymbolicTraits) (uintptr_t)
2299              CFArrayGetValueAtIndex (traits_array, j));
2300           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2302           mask_min = ((synth_sym_traits ^ sym_traits)
2303                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2304           if (FONT_SLANT_NUMERIC (spec) < 0)
2305             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2306           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2307             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2309           mask_max = (synth_sym_traits & ~sym_traits);
2310           /* Synthetic bold does not work for bitmap-only fonts on Mac
2311              OS X 10.6.  */
2312           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2313             {
2314               CFNumberRef format =
2315                 mac_font_descriptor_copy_attribute (desc,
2316                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2318               if (format)
2319                 {
2320                   uint32_t format_val;
2322                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2323                                         &format_val)
2324                       && format_val == MAC_FONT_FORMAT_BITMAP)
2325                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2326                 }
2327             }
2328           if (spacing >= 0)
2329             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2331           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2332                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2333                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2334             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2335                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2336                  bmask += MAC_FONT_TRAIT_BOLD)
2337               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2338                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2339                    imask += MAC_FONT_TRAIT_ITALIC)
2340                 {
2341                   FontSymbolicTraits synth = (imask | bmask | mmask);
2343                   if (synth == 0
2344                       || j == macfont_closest_traits_index (traits_array,
2345                                                             (sym_traits | synth)))
2346                     {
2347                       entity = macfont_descriptor_entity (desc, extra, synth);
2348                       if (! NILP (entity))
2349                         val = Fcons (entity, val);
2350                     }
2351                 }
2352         }
2354       CFRelease (traits_array);
2355       CFRelease (descs);
2356     }
2358   CFRelease (families);
2359   val = Fnreverse (val);
2360   goto finish;
2361  err:
2362   val = Qnil;
2364  finish:
2365   FONT_ADD_LOG ("macfont-list", spec, val);
2366   if (charset) CFRelease (charset);
2367   if (languages) CFRelease (languages);
2368   if (attributes) CFRelease (attributes);
2369   if (family_name) CFRelease (family_name);
2371   unblock_input ();
2373   return val;
2376 static Lisp_Object
2377 macfont_match (struct frame * frame, Lisp_Object spec)
2379   Lisp_Object entity = Qnil;
2380   CFMutableDictionaryRef attributes;
2381   FontDescriptorRef pat_desc = NULL, desc = NULL;
2383   block_input ();
2385   attributes = macfont_create_attributes_with_spec (spec);
2386   if (attributes)
2387     {
2388       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2389       CFRelease (attributes);
2390     }
2391   if (pat_desc)
2392     {
2393       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2394                                                                   NULL);
2395       CFRelease (pat_desc);
2396     }
2397   if (desc)
2398     {
2399       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2400                                           0);
2401       CFRelease (desc);
2402     }
2403   unblock_input ();
2405   FONT_ADD_LOG ("macfont-match", spec, entity);
2406   return entity;
2409 static Lisp_Object
2410 macfont_list_family (struct frame *frame)
2412   Lisp_Object list = Qnil;
2413   CFArrayRef families;
2415   block_input ();
2417   families = mac_font_create_available_families ();
2418   if (families)
2419     {
2420       CFIndex i, count = CFArrayGetCount (families);
2422       for (i = 0; i < count; i++)
2423         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2424       CFRelease (families);
2425     }
2427   unblock_input ();
2429   return list;
2432 static void
2433 macfont_free_entity (Lisp_Object entity)
2435   Lisp_Object val = assq_no_quit (QCfont_entity,
2436                                   AREF (entity, FONT_EXTRA_INDEX));
2437   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2439   block_input ();
2440   CFRelease (name);
2441   unblock_input ();
2444 static Lisp_Object
2445 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2447   Lisp_Object val, font_object;
2448   CFStringRef font_name;
2449   struct macfont_info *macfont_info = NULL;
2450   struct font *font;
2451   int size;
2452   FontRef macfont;
2453   FontSymbolicTraits sym_traits;
2454   char name[256];
2455   int len, i, total_width;
2456   CGGlyph glyph;
2457   CGFloat ascent, descent, leading;
2459   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2460   if (! CONSP (val)
2461       || XTYPE (XCDR (val)) != Lisp_Misc
2462       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2463     return Qnil;
2464   font_name = XSAVE_POINTER (XCDR (val), 0);
2465   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2467   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2468   if (size == 0)
2469     size = pixel_size;
2471   block_input ();
2472   macfont = mac_font_create_with_name (font_name, size);
2473   if (macfont)
2474     {
2475       int fontsize = (int) [((NSFont *) macfont) pointSize];
2476       if (fontsize != size) size = fontsize;
2477     }
2478   unblock_input ();
2479   if (! macfont)
2480     return Qnil;
2482   font_object = font_make_object (VECSIZE (struct macfont_info), entity, size);
2483   ASET (font_object, FONT_TYPE_INDEX, macfont_driver.type);
2484   len = font_unparse_xlfd (entity, size, name, 256);
2485   if (len > 0)
2486     ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
2487   len = font_unparse_fcname (entity, size, name, 256);
2488   if (len > 0)
2489     ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
2490   else
2491     ASET (font_object, FONT_FULLNAME_INDEX,
2492           AREF (font_object, FONT_NAME_INDEX));
2493   font = XFONT_OBJECT (font_object);
2494   font->pixel_size = size;
2495   font->driver = &macfont_driver;
2496   font->encoding_charset = font->repertory_charset = -1;
2498   block_input ();
2500   macfont_info = (struct macfont_info *) font;
2501   macfont_info->macfont = macfont;
2502   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2504   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2505   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2506     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2507                                                                   size);
2508   else
2509     macfont_info->screen_font = NULL;
2510   macfont_info->cache = macfont_lookup_cache (font_name);
2511   macfont_retain_cache (macfont_info->cache);
2512   macfont_info->metrics = NULL;
2513   macfont_info->metrics_nrows = 0;
2514   macfont_info->synthetic_italic_p = 0;
2515   macfont_info->synthetic_bold_p = 0;
2516   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2517   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2518   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2519       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2520     macfont_info->synthetic_italic_p = 1;
2521   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2522       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2523     macfont_info->synthetic_bold_p = 1;
2524   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2525     macfont_info->spacing = MACFONT_SPACING_MONO;
2526   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2527            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2528                == FONT_SPACING_SYNTHETIC_MONO))
2529     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2530   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2531     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2532   else
2533     {
2534       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2535       if (CONSP (val))
2536         macfont_info->antialias =
2537           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2538     }
2539   macfont_info->color_bitmap_p = 0;
2540   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2541     macfont_info->color_bitmap_p = 1;
2543   glyph = macfont_get_glyph_for_character (font, ' ');
2544   if (glyph != kCGFontIndexInvalid)
2545     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2546   else
2547     /* dirty workaround */
2548     font->space_width = pixel_size;
2550   total_width = font->space_width;
2551   for (i = 1; i < 95; i++)
2552     {
2553       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2554       if (glyph == kCGFontIndexInvalid)
2555         break;
2556       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2557     }
2558   if (i == 95)
2559     font->average_width = total_width / 95;
2560   else
2561     font->average_width = font->space_width; /* XXX */
2563   if (!(macfont_info->screen_font
2564         && mac_screen_font_get_metrics (macfont_info->screen_font,
2565                                         &ascent, &descent, &leading)))
2566     {
2567       CFStringRef family_name;
2569       ascent = mac_font_get_ascent (macfont);
2570       descent = mac_font_get_descent (macfont);
2571       leading = mac_font_get_leading (macfont);
2572       /* AppKit and WebKit do some adjustment to the heights of
2573          Courier, Helvetica, and Times.  */
2574       family_name = mac_font_copy_family_name (macfont);
2575       if (family_name)
2576         {
2577           if ((CFStringCompare (family_name, CFSTR ("Courier"), 0)
2578                == kCFCompareEqualTo)
2579               || (CFStringCompare (family_name, CFSTR ("Helvetica"), 0)
2580                   == kCFCompareEqualTo)
2581               || (CFStringCompare (family_name, CFSTR ("Times"), 0)
2582                   == kCFCompareEqualTo))
2583             ascent += (ascent + descent) * .15f;
2584           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2585             {
2586               leading *= .25f;
2587               ascent += leading;
2588             }
2589           CFRelease (family_name);
2590         }
2591     }
2592   font->ascent = ascent + 0.5f;
2593   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2594   if (CONSP (val) && !NILP (XCDR (val)))
2595     font->descent = descent + 0.5f;
2596   else
2597     font->descent = descent + leading + 0.5f;
2598   font->height = font->ascent + font->descent;
2600   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2601   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2603   unblock_input ();
2605   /* Unfortunately Xft doesn't provide a way to get minimum char
2606      width.  So, we use space_width instead.  */
2607   font->min_width = font->max_width = font->space_width; /* XXX */
2609   font->baseline_offset = 0;
2610   font->relative_compose = 0;
2611   font->default_ascent = 0;
2612   font->vertical_centering = 0;
2614   return font_object;
2617 static void
2618 macfont_close (struct font *font)
2620   struct macfont_info *macfont_info = (struct macfont_info *) font;
2621   int i;
2623   block_input ();
2624   CFRelease (macfont_info->macfont);
2625   CGFontRelease (macfont_info->cgfont);
2626   if (macfont_info->screen_font)
2627     CFRelease (macfont_info->screen_font);
2628   macfont_release_cache (macfont_info->cache);
2629   for (i = 0; i < macfont_info->metrics_nrows; i++)
2630     if (macfont_info->metrics[i])
2631       xfree (macfont_info->metrics[i]);
2632   if (macfont_info->metrics)
2633     xfree (macfont_info->metrics);
2634   unblock_input ();
2637 static int
2638 macfont_has_char (Lisp_Object font, int c)
2640   int result;
2641   CFCharacterSetRef charset;
2643   block_input ();
2644   if (FONT_ENTITY_P (font))
2645     {
2646       Lisp_Object val;
2647       CFStringRef name;
2649       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2650       val = XCDR (val);
2651       name = XSAVE_POINTER (val, 0);
2652       charset = macfont_get_cf_charset_for_name (name);
2653     }
2654   else
2655     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2657   result = CFCharacterSetIsLongCharacterMember (charset, c);
2658   unblock_input ();
2660   return result;
2663 static unsigned
2664 macfont_encode_char (struct font *font, int c)
2666   struct macfont_info *macfont_info = (struct macfont_info *) font;
2667   CGGlyph glyph;
2669   block_input ();
2670   glyph = macfont_get_glyph_for_character (font, c);
2671   unblock_input ();
2673   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2676 static int
2677 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2678                       struct font_metrics *metrics)
2680   int width, i;
2682   block_input ();
2683   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2684   for (i = 1; i < nglyphs; i++)
2685     {
2686       struct font_metrics m;
2687       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2688                                      NULL, 0);
2690       if (metrics)
2691         {
2692           if (width + m.lbearing < metrics->lbearing)
2693             metrics->lbearing = width + m.lbearing;
2694           if (width + m.rbearing > metrics->rbearing)
2695             metrics->rbearing = width + m.rbearing;
2696           if (m.ascent > metrics->ascent)
2697             metrics->ascent = m.ascent;
2698           if (m.descent > metrics->descent)
2699             metrics->descent = m.descent;
2700         }
2701       width += w;
2702     }
2703   unblock_input ();
2705   if (metrics)
2706     metrics->width = width;
2708   return width;
2711 static int
2712 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2713               bool with_background)
2715   struct frame * f = s->f;
2716   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2717   FontRef macfont = macfont_info->macfont;
2718   CGContextRef context;
2719   BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2720   int end = isComposite ? s->cmp_to : s->nchars;
2721   int len = end - s->cmp_from;
2722   int i;
2724   block_input ();
2726   context = [[NSGraphicsContext currentContext] graphicsPort];
2727   CGContextSaveGState (context);
2729 #if 0
2730   if (s->num_clips > 0)
2731     {
2732       CGRect clips[2];
2734       for (i = 0; i < s->num_clips; i++)
2735         clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2736                                   s->clip[i].right - s->clip[i].left,
2737                                   s->clip[i].bottom - s->clip[i].top);
2738       CGContextClipToRects (context, clips, s->num_clips);
2739     }
2740 #endif
2742   if (with_background)
2743     {
2744       CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, s);
2745       CGContextFillRect (context,
2746                          CGRectMake (x, y,
2747                                      s->width, FONT_HEIGHT (s->font)));
2748     }
2750   if (macfont_info->cgfont)
2751     {
2752       CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2753       CGPoint *positions = alloca (sizeof (CGPoint) * len);
2754       CGFloat total_width = 0;
2755       CGFloat font_size = mac_font_get_size (macfont);
2756       CGAffineTransform atfm;
2757       CGFloat advance_delta = 0;
2758       int y_draw = -s->ybase;
2759       int no_antialias_p =
2760         (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2761          || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2762              && font_size <= macfont_antialias_threshold));
2764       for (i = 0; i < len; i++)
2765         {
2766           int width;
2768           glyphs[i] = *(s->char2b + s->cmp_from + i);
2769           width = (s->padding_p ? 1
2770                    : macfont_glyph_extents (s->font, glyphs[i],
2771                                             NULL, &advance_delta,
2772                                             no_antialias_p));
2773           positions[i].x = total_width + advance_delta;
2774           positions[i].y = 0;
2775           total_width += width;
2776         }
2778       CGContextScaleCTM (context, 1, -1);
2779       CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, s);
2780       if (macfont_info->synthetic_italic_p)
2781         atfm = synthetic_italic_atfm;
2782       else
2783         atfm = CGAffineTransformIdentity;
2784       if (macfont_info->synthetic_bold_p)
2785         {
2786           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2787           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2788           CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, s);
2789         }
2790       if (no_antialias_p)
2791         CGContextSetShouldAntialias (context, false);
2793       CGContextSetTextMatrix (context, atfm);
2794       CGContextSetTextPosition (context, x, y_draw);
2796 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2797       if (macfont_info->color_bitmap_p
2798 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2799           && CTFontDrawGlyphs != NULL
2800 #endif
2801           )
2802         {
2803           if (len > 0)
2804             {
2805               CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2806             }
2807         }
2808       else
2809 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2810         {
2811           CGContextSetFont (context, macfont_info->cgfont);
2812           CGContextSetFontSize (context, font_size);
2813           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2814         }
2815     }
2817   CGContextRestoreGState (context);
2819   unblock_input ();
2821   return len;
2824 static Lisp_Object
2825 macfont_shape (Lisp_Object lgstring)
2827   struct font *font;
2828   struct macfont_info *macfont_info;
2829   FontRef macfont;
2830   ptrdiff_t glyph_len, len, i, j;
2831   CFIndex nonbmp_len;
2832   UniChar *unichars;
2833   CFIndex *nonbmp_indices;
2834   CFStringRef string;
2835   CFIndex used = 0;
2836   struct mac_glyph_layout *glyph_layouts;
2838   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2839   macfont_info = (struct macfont_info *) font;
2840   macfont = macfont_info->macfont;
2842   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2843   nonbmp_len = 0;
2844   for (i = 0; i < glyph_len; i++)
2845     {
2846       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2848       if (NILP (lglyph))
2849         break;
2850       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2851         nonbmp_len++;
2852     }
2854   len = i;
2856   if (INT_MAX / 2 < len)
2857     memory_full (SIZE_MAX);
2859   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2860   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2861   for (i = j = 0; i < len; i++)
2862     {
2863       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2865       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2866         {
2867           nonbmp_indices[j] = i + j;
2868           j++;
2869         }
2870     }
2871   nonbmp_indices[j] = len + j;  /* sentinel */
2873   block_input ();
2875   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2876                                                kCFAllocatorNull);
2877   if (string)
2878     {
2879       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2880       if (macfont_info->screen_font)
2881         used = mac_screen_font_shape (macfont_info->screen_font, string,
2882                                       glyph_layouts, glyph_len);
2883       else
2884         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2885       CFRelease (string);
2886     }
2888   unblock_input ();
2890   if (used == 0)
2891     return Qnil;
2893   block_input ();
2895   for (i = 0; i < used; i++)
2896     {
2897       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2898       struct mac_glyph_layout *gl = glyph_layouts + i;
2899       EMACS_INT from, to;
2900       struct font_metrics metrics;
2901       int xoff, yoff, wadjust;
2903       if (NILP (lglyph))
2904         {
2905           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2906           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2907         }
2909       from = gl->comp_range.location;
2910       /* Convert UTF-16 index to UTF-32.  */
2911       j = 0;
2912       while (nonbmp_indices[j] < from)
2913         j++;
2914       from -= j;
2915       LGLYPH_SET_FROM (lglyph, from);
2917       to = gl->comp_range.location + gl->comp_range.length;
2918       /* Convert UTF-16 index to UTF-32.  */
2919       while (nonbmp_indices[j] < to)
2920         j++;
2921       to -= j;
2922       LGLYPH_SET_TO (lglyph, to - 1);
2924       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2925          the composition is trivial.  */
2926       {
2927         UTF32Char c;
2929         if (unichars[gl->string_index] >= 0xD800
2930             && unichars[gl->string_index] < 0xDC00)
2931           c = (((unichars[gl->string_index] - 0xD800) << 10)
2932                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2933         else
2934           c = unichars[gl->string_index];
2935         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2936           c = 0;
2937         LGLYPH_SET_CHAR (lglyph, c);
2938       }
2940       {
2941         unsigned long cc = gl->glyph_id;
2942         LGLYPH_SET_CODE (lglyph, cc);
2943       }
2945       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2946       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2947       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2948       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2949       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2950       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2952       xoff = lround (gl->advance_delta);
2953       yoff = lround (- gl->baseline_delta);
2954       wadjust = lround (gl->advance);
2955       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2956         {
2957           Lisp_Object vec;
2959           vec = Fmake_vector (make_number (3), Qnil);
2960           ASET (vec, 0, make_number (xoff));
2961           ASET (vec, 1, make_number (yoff));
2962           ASET (vec, 2, make_number (wadjust));
2963           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2964         }
2965     }
2967   unblock_input ();
2969   return make_number (used);
2972 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2973 typedef UInt8 UINT24[3];
2975 #pragma pack(push, 1)
2976 struct variation_selector_record
2978   UINT24 var_selector;
2979   UInt32 default_uvs_offset, non_default_uvs_offset;
2981 struct uvs_table
2983   UInt16 format;
2984   UInt32 length, num_var_selector_records;
2985   struct variation_selector_record variation_selector_records[1];
2987 #define SIZEOF_UVS_TABLE_HEADER \
2988   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2990 struct unicode_value_range
2992   UINT24 start_unicode_value;
2993   UInt8 additional_count;
2995 struct default_uvs_table {
2996   UInt32 num_unicode_value_ranges;
2997   struct unicode_value_range unicode_value_ranges[1];
2999 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3000   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3002 struct uvs_mapping
3004   UINT24 unicode_value;
3005   UInt16 glyph_id;
3007 struct non_default_uvs_table
3009   UInt32 num_uvs_mappings;
3010   struct uvs_mapping uvs_mappings[1];
3012 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3013   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3014 #pragma pack(pop)
3016 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3017 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3018    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3019    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3020 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3021 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3022 /* Succeeding one byte should also be accessible.  */
3023 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3024 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3026 /* Return UVS subtable for the specified FONT.  If the subtable is not
3027    found or ill-formatted, then return NULL.  */
3029 static CFDataRef
3030 mac_font_copy_uvs_table (FontRef font)
3032   CFDataRef cmap_table, uvs_table = NULL;
3034   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3035   if (cmap_table)
3036     {
3037       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3038       struct uvs_table *uvs;
3039       struct variation_selector_record *records;
3040       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3042 #if __LP64__
3043       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3044         goto finish;
3045 #endif
3047       cmap_len = CFDataGetLength (cmap_table);
3048       if (sizeof_sfntCMapHeader > cmap_len)
3049         goto finish;
3051       ntables = BUINT16_VALUE (cmap->numTables);
3052       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3053                      / sizeof_sfntCMapEncoding))
3054         goto finish;
3056       for (i = 0; i < ntables; i++)
3057         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3058              == kFontUnicodePlatform)
3059             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3060                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3061           {
3062             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3063             break;
3064           }
3065       if (i == ntables
3066           || uvs_offset > cmap_len
3067           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3068         goto finish;
3070       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3071       uvs_len = BUINT32_VALUE (uvs->length);
3072       if (uvs_len > cmap_len - uvs_offset
3073           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3074         goto finish;
3076       if (BUINT16_VALUE (uvs->format) != 14)
3077         goto finish;
3079       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3080       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3081                       / sizeof (struct variation_selector_record)))
3082         goto finish;
3084       records = uvs->variation_selector_records;
3085       for (i = 0; i < nrecords; i++)
3086         {
3087           UInt32 default_uvs_offset, non_default_uvs_offset;
3089           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3090           if (default_uvs_offset)
3091             {
3092               struct default_uvs_table *default_uvs;
3093               UInt32 nranges;
3095               if (default_uvs_offset > uvs_len
3096                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3097                       > uvs_len - default_uvs_offset))
3098                 goto finish;
3100               default_uvs = ((struct default_uvs_table *)
3101                              ((UInt8 *) uvs + default_uvs_offset));
3102               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3103               if (nranges > ((uvs_len - default_uvs_offset
3104                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3105                              / sizeof (struct unicode_value_range)))
3106                 goto finish;
3107               /* Now 2 * nranges can't overflow, so we can safely use
3108                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3109                  mac_font_get_glyphs_for_variants.  */
3110             }
3112           non_default_uvs_offset =
3113             BUINT32_VALUE (records[i].non_default_uvs_offset);
3114           if (non_default_uvs_offset)
3115             {
3116               struct non_default_uvs_table *non_default_uvs;
3117               UInt32 nmappings;
3119               if (non_default_uvs_offset > uvs_len
3120                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3121                       > uvs_len - non_default_uvs_offset))
3122                 goto finish;
3124               non_default_uvs = ((struct non_default_uvs_table *)
3125                                  ((UInt8 *) uvs + non_default_uvs_offset));
3126               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3127               if (nmappings > ((uvs_len - non_default_uvs_offset
3128                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3129                                / sizeof (struct uvs_mapping)))
3130                 goto finish;
3131               /* Now 2 * nmappings can't overflow, so we can safely
3132                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3133                  in mac_font_get_glyphs_for_variants.  */
3134             }
3135         }
3137       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3139     finish:
3140       CFRelease (cmap_table);
3141     }
3143   return uvs_table;
3146 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3147    sequence consisting of the given base character C and each
3148    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3149    result (explained below) into the corresponding GLYPHS[i].  If the
3150    entry is found in the Default UVS Table, then the result is 0.  If
3151    the entry is found in the Non-Default UVS Table, then the result is
3152    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3153    elements in SELECTORS must be sorted in strictly increasing
3154    order.  */
3156 static void
3157 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3158                                   const UTF32Char selectors[], CGGlyph glyphs[],
3159                                   CFIndex count)
3161   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3162   struct variation_selector_record *records = uvs->variation_selector_records;
3163   CFIndex i;
3164   UInt32 ir, nrecords;
3165 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3166   dispatch_queue_t queue =
3167     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3168   dispatch_group_t group = dispatch_group_create ();
3169 #endif
3171   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3172   i = 0;
3173   ir = 0;
3174   while (i < count && ir < nrecords)
3175     {
3176       UInt32 default_uvs_offset, non_default_uvs_offset;
3178       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3179         {
3180           glyphs[i++] = kCGFontIndexInvalid;
3181           continue;
3182         }
3183       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3184         {
3185           ir++;
3186           continue;
3187         }
3189       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3190       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3191       non_default_uvs_offset =
3192         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3193 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3194       dispatch_group_async (group, queue, ^{
3195 #endif
3196           glyphs[i] = kCGFontIndexInvalid;
3198           if (default_uvs_offset)
3199             {
3200               struct default_uvs_table *default_uvs =
3201                 (struct default_uvs_table *) ((UInt8 *) uvs
3202                                               + default_uvs_offset);
3203               struct unicode_value_range *ranges =
3204                 default_uvs->unicode_value_ranges;
3205               UInt32 lo, hi;
3207               lo = 0;
3208               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3209               while (lo < hi)
3210                 {
3211                   UInt32 mid = (lo + hi) / 2;
3213                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3214                     hi = mid;
3215                   else
3216                     lo = mid + 1;
3217                 }
3218               if (hi > 0
3219                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3220                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3221                 glyphs[i] = 0;
3222             }
3224           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3225             {
3226               struct non_default_uvs_table *non_default_uvs =
3227                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3228                                                   + non_default_uvs_offset);
3229               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3230               UInt32 lo, hi;
3232               lo = 0;
3233               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3234               while (lo < hi)
3235                 {
3236                   UInt32 mid = (lo + hi) / 2;
3238                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3239                     hi = mid;
3240                   else
3241                     lo = mid + 1;
3242                 }
3243               if (hi > 0 &&
3244                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3245                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3246             }
3247 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3248         });
3249 #endif
3250       i++;
3251       ir++;
3252     }
3253   while (i < count)
3254     glyphs[i++] = kCGFontIndexInvalid;
3255 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3256   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3257   dispatch_release (group);
3258 #endif
3261 static int
3262 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3264   CFDataRef uvs_table;
3265   CharacterCollection uvs_collection;
3266   int i, n = 0;
3268   block_input ();
3269   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3271   if (uvs_table)
3272     {
3273       UTF32Char selectors[256];
3274       CGGlyph glyphs[256];
3276       for (i = 0; i < 16; i++)
3277         selectors[i] = 0xFE00 + i;
3278       for (; i < 256; i++)
3279         selectors[i] = 0xE0100 + (i - 16);
3280       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3281       for (i = 0; i < 256; i++)
3282         {
3283           CGGlyph glyph = glyphs[i];
3285           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3286               && glyph != kCGFontIndexInvalid)
3287             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3288           if (glyph == kCGFontIndexInvalid)
3289             variations[i] = 0;
3290           else
3291             {
3292               variations[i] = (glyph ? glyph
3293                                : macfont_get_glyph_for_character (font, c));
3294               n++;
3295             }
3296         }
3297     }
3298   unblock_input ();
3300   return n;
3303 static const char *const macfont_booleans[] = {
3304   ":antialias",
3305   ":minspace",
3306   NULL,
3309 static const char *const macfont_non_booleans[] = {
3310   ":lang",
3311   ":script",
3312   ":destination",
3313   NULL,
3316 static void
3317 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3319   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3322 static Boolean
3323 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3324                                           CFArrayRef languages)
3326   Boolean result = true;
3327   CFArrayRef desc_languages =
3328     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3330   if (desc_languages == NULL)
3331     result = false;
3332   else
3333     {
3334       CFIndex desc_languages_count, i, languages_count;
3336       desc_languages_count = CFArrayGetCount (desc_languages);
3337       languages_count = CFArrayGetCount (languages);
3338       for (i = 0; i < languages_count; i++)
3339         if (!CFArrayContainsValue (desc_languages,
3340                                    CFRangeMake (0, desc_languages_count),
3341                                    CFArrayGetValueAtIndex (languages, i)))
3342           {
3343             result = false;
3344             break;
3345           }
3346       CFRelease (desc_languages);
3347     }
3349   return result;
3352 static CFStringRef
3353 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3355   CFStringRef result = NULL;
3356   CFStringRef charset_string =
3357     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3359   if (charset_string && CFStringGetLength (charset_string) > 0)
3360     {
3361       CFStringRef keys[] = {
3362 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3363         kCTLanguageAttributeName
3364 #else
3365         CFSTR ("NSLanguage")
3366 #endif
3367       };
3368       CFTypeRef values[] = {NULL};
3369       CFIndex num_values = 0;
3370       CFArrayRef languages
3371         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3373       if (languages && CFArrayGetCount (languages) > 0)
3374         {
3375           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3376             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3377           else
3378             {
3379               CFCharacterSetRef charset =
3380                 CFDictionaryGetValue (attributes,
3381                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3383               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3384             }
3385         }
3386       if (result == NULL)
3387         {
3388           CFAttributedStringRef attr_string = NULL;
3389           CTLineRef ctline = NULL;
3390           CFDictionaryRef attrs
3391             = CFDictionaryCreate (NULL, (const void **) keys,
3392                                   (const void **) values, num_values,
3393                                   &kCFTypeDictionaryKeyCallBacks,
3394                                   &kCFTypeDictionaryValueCallBacks);
3396           if (attrs)
3397             {
3398               attr_string = CFAttributedStringCreate (NULL, charset_string,
3399                                                       attrs);
3400               CFRelease (attrs);
3401             }
3402           if (attr_string)
3403             {
3404               ctline = CTLineCreateWithAttributedString (attr_string);
3405               CFRelease (attr_string);
3406             }
3407           if (ctline)
3408             {
3409               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3410               CFIndex i, nruns = CFArrayGetCount (runs);
3411               CTFontRef font;
3413               for (i = 0; i < nruns; i++)
3414                 {
3415                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3416                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3417                   CTFontRef font_in_run;
3419                   if (attributes == NULL)
3420                     break;
3421                   font_in_run =
3422                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3423                   if (font_in_run == NULL)
3424                     break;
3425                   if (i == 0)
3426                     font = font_in_run;
3427                   else if (!mac_ctfont_equal_in_postscript_name (font,
3428                                                                  font_in_run))
3429                     break;
3430                 }
3431               if (nruns > 0 && i == nruns)
3432                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3433               CFRelease (ctline);
3434             }
3435         }
3436     }
3438   return result;
3441 static inline double
3442 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3444   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3445                                      &glyph, NULL, 1);
3448 static inline CGRect
3449 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3451   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3452                                           &glyph, NULL, 1);
3455 static CFArrayRef
3456 mac_ctfont_create_available_families (void)
3458   CFMutableArrayRef families = NULL;
3460 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3461 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3462   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3463 #endif
3464     {
3465       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3467       if (orig_families)
3468         {
3469           CFIndex i, count = CFArrayGetCount (orig_families);
3471           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3472           if (families)
3473             for (i = 0; i < count; i++)
3474               {
3475                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3477                 if (!CFStringHasPrefix (family, CFSTR ("."))
3478                     && (CTFontManagerCompareFontFamilyNames (family,
3479                                                              CFSTR ("LastResort"),
3480                                                              NULL)
3481                         != kCFCompareEqualTo))
3482                   CFArrayAppendValue (families, family);
3483               }
3484           CFRelease (orig_families);
3485         }
3486     }
3487 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3488   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3489 #endif
3490 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3491 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3492     {
3493       CTFontCollectionRef collection;
3494       CFArrayRef descs = NULL;
3496       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3497       if (collection)
3498         {
3499           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3500           CFRelease (collection);
3501         }
3502       if (descs)
3503         {
3504           CFIndex i, count = CFArrayGetCount (descs);
3506           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3507           if (families)
3508             for (i = 0; i < count; i++)
3509               {
3510                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3511                 CFStringRef name =
3512                   mac_font_descriptor_copy_attribute (desc,
3513                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3515                 if (name)
3516                   {
3517                     CFIndex p, limit = CFArrayGetCount (families);
3519                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3520                                               (const void *) name,
3521                                               mac_font_family_compare, NULL);
3522                     if (p >= limit)
3523                       CFArrayAppendValue (families, name);
3524                     else if (mac_font_family_compare
3525                              (CFArrayGetValueAtIndex (families, p),
3526                               name, NULL) != kCFCompareEqualTo)
3527                       CFArrayInsertValueAtIndex (families, p, name);
3528                     CFRelease (name);
3529                   }
3530               }
3531           CFRelease (descs);
3532         }
3533     }
3534 #endif
3536   return families;
3539 static Boolean
3540 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3542   Boolean result;
3543   CFStringRef name1, name2;
3545   if (font1 == font2)
3546     return true;
3548   result = false;
3549   name1 = CTFontCopyPostScriptName (font1);
3550   if (name1)
3551     {
3552       name2 = CTFontCopyPostScriptName (font2);
3553       if (name2)
3554         {
3555           result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3556           CFRelease (name2);
3557         }
3558       CFRelease (name1);
3559     }
3561   return result;
3564 static CTLineRef
3565 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3566                                              CTFontRef macfont)
3568   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3569   CFTypeRef values[] = {NULL, NULL};
3570   CFDictionaryRef attributes = NULL;
3571   CFAttributedStringRef attr_string = NULL;
3572   CTLineRef ctline = NULL;
3573   float float_zero = 0.0f;
3575   values[0] = macfont;
3576   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3577   if (values[1])
3578     {
3579       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3580                                        (const void **) values,
3581                                        sizeof (keys) / sizeof (keys[0]),
3582                                        &kCFTypeDictionaryKeyCallBacks,
3583                                        &kCFTypeDictionaryValueCallBacks);
3584       CFRelease (values[1]);
3585     }
3586   if (attributes)
3587     {
3588       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3589       CFRelease (attributes);
3590     }
3591   if (attr_string)
3592     {
3593       ctline = CTLineCreateWithAttributedString (attr_string);
3594       CFRelease (attr_string);
3595     }
3596   if (ctline)
3597     {
3598       /* Abandon if ctline contains some fonts other than the
3599          specified one.  */
3600       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3601       CFIndex i, nruns = CFArrayGetCount (runs);
3603       for (i = 0; i < nruns; i++)
3604         {
3605           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3606           CFDictionaryRef attributes = CTRunGetAttributes (run);
3607           CTFontRef font_in_run;
3609           if (attributes == NULL)
3610             break;
3611           font_in_run =
3612             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3613           if (font_in_run == NULL)
3614             break;
3615           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3616             break;
3617         }
3618       if (i < nruns)
3619         {
3620           CFRelease (ctline);
3621           ctline = NULL;
3622         }
3623     }
3625   return ctline;
3628 static CFIndex
3629 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3630                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3632   CFIndex used, result = 0;
3633   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3635   if (ctline == NULL)
3636     return 0;
3638   used = CTLineGetGlyphCount (ctline);
3639   if (used <= glyph_len)
3640     {
3641       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3642       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3643       CGFloat total_advance = 0;
3644       CFIndex total_glyph_count = 0;
3646       for (k = 0; k < ctrun_count; k++)
3647         {
3648           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3649           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3650           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3651           CFRange string_range, comp_range, range;
3652           CFIndex *permutation;
3654           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3655             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3656           else
3657             permutation = NULL;
3659 #define RIGHT_TO_LEFT_P permutation
3661           /* Now the `comp_range' member of struct mac_glyph_layout is
3662              temporarily used as a work area such that:
3663               glbuf[i].comp_range.location =
3664                 min {compRange[i + 1].location, ...,
3665                      compRange[glyph_count - 1].location,
3666                      maxRange (stringRangeForCTRun)}
3667               glbuf[i].comp_range.length = maxRange (compRange[i])
3668              where compRange[i] is the range of composed characters
3669              containing i-th glyph.  */
3670           string_range = CTRunGetStringRange (ctrun);
3671           min_location = string_range.location + string_range.length;
3672           for (i = 0; i < glyph_count; i++)
3673             {
3674               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3675               CFIndex glyph_index;
3676               CFRange rng;
3678               if (!RIGHT_TO_LEFT_P)
3679                 glyph_index = glyph_count - i - 1;
3680               else
3681                 glyph_index = i;
3682               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3683                                      &gl->string_index);
3684               rng =
3685                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3686                                                              gl->string_index);
3687               gl->comp_range.location = min_location;
3688               gl->comp_range.length = rng.location + rng.length;
3689               if (rng.location < min_location)
3690                 min_location = rng.location;
3691             }
3693           /* Fill the `comp_range' member of struct mac_glyph_layout,
3694              and setup a permutation for right-to-left text.  */
3695           comp_range = CFRangeMake (string_range.location, 0);
3696           range = CFRangeMake (0, 0);
3697           while (1)
3698             {
3699               struct mac_glyph_layout *gl =
3700                 glbuf + range.location + range.length;
3702               if (gl->comp_range.length
3703                   > comp_range.location + comp_range.length)
3704                 comp_range.length = gl->comp_range.length - comp_range.location;
3705               min_location = gl->comp_range.location;
3706               range.length++;
3708               if (min_location >= comp_range.location + comp_range.length)
3709                 {
3710                   comp_range.length = min_location - comp_range.location;
3711                   for (i = 0; i < range.length; i++)
3712                     {
3713                       glbuf[range.location + i].comp_range = comp_range;
3714                       if (RIGHT_TO_LEFT_P)
3715                         permutation[range.location + i] =
3716                           range.location + range.length - i - 1;
3717                     }
3719                   comp_range = CFRangeMake (min_location, 0);
3720                   range.location += range.length;
3721                   range.length = 0;
3722                   if (range.location == glyph_count)
3723                     break;
3724                 }
3725             }
3727           /* Then fill the remaining members.  */
3728           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3729                range.location++)
3730             {
3731               struct mac_glyph_layout *gl;
3732               CGPoint position;
3734               if (!RIGHT_TO_LEFT_P)
3735                 gl = glbuf + range.location;
3736               else
3737                 {
3738                   CFIndex src, dest;
3740                   src = glyph_count - 1 - range.location;
3741                   dest = permutation[src];
3742                   gl = glbuf + dest;
3743                   if (src < dest)
3744                     {
3745                       CFIndex tmp = gl->string_index;
3747                       gl->string_index = glbuf[src].string_index;
3748                       glbuf[src].string_index = tmp;
3749                     }
3750                 }
3751               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3753               CTRunGetPositions (ctrun, range, &position);
3754               gl->advance_delta = position.x - total_advance;
3755               gl->baseline_delta = position.y;
3756               gl->advance = (gl->advance_delta
3757                              + CTRunGetTypographicBounds (ctrun, range,
3758                                                           NULL, NULL, NULL));
3759               total_advance += gl->advance;
3760             }
3762           if (RIGHT_TO_LEFT_P)
3763             xfree (permutation);
3765 #undef RIGHT_TO_LEFT_P
3767           total_glyph_count += glyph_count;
3768         }
3770       result = used;
3771     }
3772   CFRelease (ctline);
3774   return result;
3777 /* The function below seems to cause a memory leak for the CFString
3778    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3779    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3780 #if USE_CT_GLYPH_INFO
3781 static CGGlyph
3782 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3783                               CGFontIndex cid)
3785   CGGlyph result = kCGFontIndexInvalid;
3786   UniChar characters[] = {0xfffd};
3787   CFStringRef string;
3788   CFAttributedStringRef attr_string = NULL;
3789   CTLineRef ctline = NULL;
3791   string = CFStringCreateWithCharacters (NULL, characters,
3792                                          sizeof (characters)
3793                                          / sizeof (characters[0]));
3794   if (string)
3795     {
3796       CTGlyphInfoRef glyph_info =
3797         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3798       CFDictionaryRef attributes = NULL;
3800       if (glyph_info)
3801         {
3802           CFStringRef keys[] = {kCTFontAttributeName,
3803                                 kCTGlyphInfoAttributeName};
3804           CFTypeRef values[] = {font, glyph_info};
3806           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3807                                            (const void **) values,
3808                                            sizeof (keys) / sizeof (keys[0]),
3809                                            &kCFTypeDictionaryKeyCallBacks,
3810                                            &kCFTypeDictionaryValueCallBacks);
3811           CFRelease (glyph_info);
3812         }
3813       if (attributes)
3814         {
3815           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3816           CFRelease (attributes);
3817         }
3818       CFRelease (string);
3819     }
3820   if (attr_string)
3821     {
3822       ctline = CTLineCreateWithAttributedString (attr_string);
3823       CFRelease (attr_string);
3824     }
3825   if (ctline)
3826     {
3827       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3829       if (CFArrayGetCount (runs) > 0)
3830         {
3831           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3832           CFDictionaryRef attributes = CTRunGetAttributes (run);
3834           if (attributes)
3835             {
3836               CTFontRef font_in_run =
3837                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3839               if (font_in_run
3840                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3841                 {
3842                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3843                   if (result >= CTFontGetGlyphCount (font))
3844                     result = kCGFontIndexInvalid;
3845                 }
3846             }
3847         }
3848       CFRelease (ctline);
3849     }
3851   return result;
3853 #endif
3855 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3856 static inline int
3857 mac_font_family_group (CFStringRef family)
3859   if (CFStringHasPrefix (family, CFSTR ("#")))
3860     return 2;
3861   else
3862     {
3863       CFRange range;
3865       range = CFStringFind (family, CFSTR ("Apple"),
3866                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3867       if (range.location != kCFNotFound)
3868         return 1;
3870       return 0;
3871     }
3874 static CFComparisonResult
3875 mac_font_family_compare (const void *val1, const void *val2, void *context)
3877   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3878   int group1, group2;
3880   group1 = mac_font_family_group (family1);
3881   group2 = mac_font_family_group (family2);
3882   if (group1 < group2)
3883     return kCFCompareLessThan;
3884   if (group1 > group2)
3885     return kCFCompareGreaterThan;
3886   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3888 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3890 static CFArrayRef
3891 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3893   CFArrayRef result = NULL;
3895 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3896 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3897   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3898 #endif
3899     {
3900       CTFontRef user_font =
3901         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3903       if (user_font)
3904         {
3905           CFArrayRef languages =
3906             CFArrayCreate (NULL, (const void **) &language, 1,
3907                            &kCFTypeArrayCallBacks);
3909           if (languages)
3910             {
3911               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3912                                                                  languages);
3913               CFRelease (languages);
3914             }
3915           CFRelease (user_font);
3916         }
3917     }
3918 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3919   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3920 #endif
3921 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3922 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3923     {
3924       CFIndex i;
3926       for (i = 0; macfont_language_default_font_names[i].language; i++)
3927         {
3928           if (CFStringCompare (macfont_language_default_font_names[i].language,
3929                                language, 0) == kCFCompareEqualTo)
3930             {
3931               CFMutableArrayRef descriptors =
3932                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3934               if (descriptors)
3935                 {
3936                   CFIndex j;
3938                   for (j = 0;
3939                        macfont_language_default_font_names[i].font_names[j];
3940                        j++)
3941                     {
3942                       CFDictionaryRef attributes =
3943                         CFDictionaryCreate (NULL,
3944                                             ((const void **)
3945                                              &MAC_FONT_NAME_ATTRIBUTE),
3946                                             ((const void **)
3947                                              &macfont_language_default_font_names[i].font_names[j]),
3948                                             1, &kCFTypeDictionaryKeyCallBacks,
3949                                             &kCFTypeDictionaryValueCallBacks);
3951                       if (attributes)
3952                         {
3953                           FontDescriptorRef pat_desc =
3954                             mac_font_descriptor_create_with_attributes (attributes);
3956                           if (pat_desc)
3957                             {
3958                               FontDescriptorRef descriptor =
3959                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3961                               if (descriptor)
3962                                 {
3963                                   CFArrayAppendValue (descriptors, descriptor);
3964                                   CFRelease (descriptor);
3965                                 }
3966                               CFRelease (pat_desc);
3967                             }
3968                           CFRelease (attributes);
3969                         }
3970                     }
3971                   result = descriptors;
3972                 }
3973               break;
3974             }
3975         }
3976     }
3977 #endif
3979   return result;
3982 static CFStringRef
3983 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3984                                                       CFArrayRef languages)
3986   CFStringRef result = NULL;
3987   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3988   CFArrayRef descriptors =
3989     mac_font_copy_default_descriptors_for_language (language);
3991   if (descriptors)
3992     {
3993       CFIndex i, count = CFArrayGetCount (descriptors);
3995       for (i = 0; i < count; i++)
3996         {
3997           FontDescriptorRef descriptor =
3998             CFArrayGetValueAtIndex (descriptors, i);
4000           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4001                                                         Qnil, languages))
4002             {
4003               CFStringRef family =
4004                 mac_font_descriptor_copy_attribute (descriptor,
4005                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4006               if (family)
4007                 {
4008                   if (!CFStringHasPrefix (family, CFSTR ("."))
4009                       && (CFStringCompare (family, CFSTR ("LastResort"), 0)
4010                           != kCFCompareEqualTo))
4011                     {
4012                       result = family;
4013                       break;
4014                     }
4015                   else
4016                     CFRelease (family);
4017                 }
4018             }
4019         }
4020       CFRelease (descriptors);
4021     }
4023   return result;
4026 void *
4027 macfont_get_nsctfont (struct font *font)
4029   struct macfont_info *macfont_info = (struct macfont_info *) font;
4030   FontRef macfont = macfont_info->macfont;
4032   return (void *) macfont;
4035 void
4036 mac_register_font_driver (struct frame *f)
4038   register_font_driver (&macfont_driver, f);
4041 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4044 void
4045 syms_of_macfont (void)
4047 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4048   static struct font_driver mac_font_driver;
4050   DEFSYM (Qmac_ct, "mac-ct");
4051   macfont_driver.type = Qmac_ct;
4052   register_font_driver (&macfont_driver, NULL);
4054   DEFSYM (QCdestination, ":destination");
4055   DEFSYM (QCminspace, ":minspace");
4056 #endif