* lisp/emacs-lisp/package.el (package--with-work-buffer-async):
[emacs.git] / src / macfont.m
blob02dc46824e993106bdb9ae2e0a9d61d4e0c1070e
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2015 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
22 #include <config.h>
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "frame.h"
27 #include "blockinput.h"
28 #include "character.h"
29 #include "charset.h"
30 #include "composite.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "termchar.h"
34 #include "nsgui.h"
35 #include "nsterm.h"
36 #include "macfont.h"
37 #include "macuvs.h"
39 #include <libkern/OSByteOrder.h>
41 static struct font_driver macfont_driver;
43 static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
44 static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
45 static CFArrayRef mac_ctfont_create_available_families (void);
46 static Boolean mac_ctfont_equal_in_postscript_name (CTFontRef, CTFontRef);
47 static CTLineRef mac_ctfont_create_line_with_string_and_font (CFStringRef,
48                                                               CTFontRef);
49 static CFComparisonResult mac_font_family_compare (const void *,
50                                                    const void *, void *);
51 static Boolean mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef,
52                                                          CFArrayRef);
53 static CFStringRef mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef);
54 static CFIndex mac_ctfont_shape (CTFontRef, CFStringRef,
55                                  struct mac_glyph_layout *, CFIndex);
56 static CFArrayRef
57 mac_font_copy_default_descriptors_for_language (CFStringRef language);
59 static CFStringRef
60 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
61                                                       CFArrayRef languages);
63 #if USE_CT_GLYPH_INFO
64 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef,
65                                              CTCharacterCollection,
66                                              CGFontIndex);
67 #endif
69 struct macfont_metrics;
71 /* The actual structure for Mac font that can be cast to struct font.  */
73 struct macfont_info
75   struct font font;
76   FontRef macfont;
77   CGFontRef cgfont;
78   ScreenFontRef screen_font;
79   struct macfont_cache *cache;
80   struct macfont_metrics **metrics;
81   short metrics_nrows;
82   bool_bf synthetic_italic_p : 1;
83   bool_bf synthetic_bold_p : 1;
84   unsigned spacing : 2;
85   unsigned antialias : 2;
86   bool_bf color_bitmap_p : 1;
89 /* Values for the `spacing' member in `struct macfont_info'.  */
91 enum
92   {
93     MACFONT_SPACING_PROPORTIONAL,
94     MACFONT_SPACING_MONO,
95     MACFONT_SPACING_SYNTHETIC_MONO,
96   };
98 /* Values for the `antialias' member in `struct macfont_info'.  */
100 enum
101   {
102     MACFONT_ANTIALIAS_DEFAULT,
103     MACFONT_ANTIALIAS_OFF,
104     MACFONT_ANTIALIAS_ON,
105   };
107 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
108 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
109 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
111 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
112 static const CGFloat synthetic_bold_factor = 0.024;
114 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
115                                                         FontSymbolicTraits *);
116 static void macfont_store_descriptor_attributes (FontDescriptorRef,
117                                                  Lisp_Object);
118 static Lisp_Object macfont_descriptor_entity (FontDescriptorRef,
119                                               Lisp_Object,
120                                               FontSymbolicTraits);
121 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
122 static int macfont_glyph_extents (struct font *, CGGlyph,
123                                   struct font_metrics *, CGFloat *, int);
124 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
125 static Boolean macfont_supports_charset_and_languages_p (FontDescriptorRef,
126                                                          CFCharacterSetRef,
127                                                          Lisp_Object,
128                                                          CFArrayRef);
129 static Boolean macfont_closest_traits_index_p (CFArrayRef, FontSymbolicTraits,
130                                                CFIndex);
131 static CFDataRef mac_font_copy_uvs_table (FontRef);
132 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
133                                               const UTF32Char [],
134                                               CGGlyph [], CFIndex);
136 /* From CFData to a lisp string.  Always returns a unibyte string.  */
138 static Lisp_Object
139 cfdata_to_lisp (CFDataRef data)
141   CFIndex len = CFDataGetLength (data);
142   Lisp_Object result = make_uninit_string (len);
144   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
146   return result;
151 /* From CFString to a lisp string.  Returns a unibyte string
152    containing a UTF-8 byte sequence.  */
154 static Lisp_Object
155 cfstring_to_lisp_nodecode (CFStringRef string)
157   Lisp_Object result = Qnil;
158   CFDataRef data;
159   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
161   if (s)
162     {
163       CFIndex i, length = CFStringGetLength (string);
165       for (i = 0; i < length; i++)
166         if (CFStringGetCharacterAtIndex (string, i) == 0)
167           break;
169       if (i == length)
170         return make_unibyte_string (s, strlen (s));
171     }
173   data = CFStringCreateExternalRepresentation (NULL, string,
174                                                kCFStringEncodingUTF8, '?');
175   if (data)
176     {
177       result = cfdata_to_lisp (data);
178       CFRelease (data);
179     }
181   return result;
184 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
185    cfstring_create_with_utf8_cstring, this function preserves NUL
186    characters.  */
188 static CFStringRef
189 cfstring_create_with_string_noencode (Lisp_Object s)
191   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
192                                                 kCFStringEncodingUTF8, false);
194   if (string == NULL)
195     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
196     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
197                                       kCFStringEncodingMacRoman, false);
199   return string;
202 static CGFloat
203 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
205   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
207   return advancement.width;
210 static CGGlyph
211 mac_font_get_glyph_for_cid (FontRef font, CharacterCollection collection,
212                             CGFontIndex cid)
214 #if USE_CT_GLYPH_INFO
215   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
216 #else
217   {
218     CGGlyph result = kCGFontIndexInvalid;
219     NSFont *nsFont = (NSFont *) font;
220     unichar characters[] = {0xfffd};
221     NSString *string =
222       [NSString stringWithCharacters:characters
223                               length:ARRAYELTS (characters)];
224     NSGlyphInfo *glyphInfo =
225       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
226                                          collection:collection
227                                          baseString:string];
228     NSDictionary *attributes =
229       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
230                     glyphInfo,NSGlyphInfoAttributeName,nil];
231     NSTextStorage *textStorage =
232       [[NSTextStorage alloc] initWithString:string
233                                  attributes:attributes];
234     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
235     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
236     NSFont *fontInTextStorage;
238     [layoutManager addTextContainer:textContainer];
239     [textContainer release];
240     [textStorage addLayoutManager:layoutManager];
241     [layoutManager release];
243     /* Force layout.  */
244     (void) [layoutManager glyphRangeForTextContainer:textContainer];
246     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
247                                 effectiveRange:NULL];
248     if (fontInTextStorage == nsFont
249         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
250       {
251         NSGlyph glyph = [layoutManager glyphAtIndex:0];
253         if (glyph < [nsFont numberOfGlyphs])
254           result = glyph;
255       }
257     [textStorage release];
259     return result;
260   }
262 #endif
264 static ScreenFontRef
265 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
267   NSFont *result, *font;
269   font = [NSFont fontWithName:((NSString *) name) size:size];
270   result = [font screenFont];
272   return (ScreenFontRef)[result retain];
276 static Boolean
277 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
278                              CGFloat *descent, CGFloat *leading)
280   NSFont *nsFont = [(NSFont *)font printerFont];
281   NSTextStorage *textStorage;
282   NSLayoutManager *layoutManager;
283   NSTextContainer *textContainer;
284   NSRect usedRect;
285   NSPoint spaceLocation;
286   CGFloat descender;
288   textStorage = [[NSTextStorage alloc] initWithString:@" "];
289   layoutManager = [[NSLayoutManager alloc] init];
290   textContainer = [[NSTextContainer alloc] init];
292   [textStorage setFont:nsFont];
293   [textContainer setLineFragmentPadding:0];
294   [layoutManager setUsesScreenFonts:YES];
296   [layoutManager addTextContainer:textContainer];
297   [textContainer release];
298   [textStorage addLayoutManager:layoutManager];
299   [layoutManager release];
301   if (!(textStorage && layoutManager && textContainer))
302     {
303       [textStorage release];
305       return false;
306     }
308   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
309                                                  effectiveRange:NULL];
310   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
311   [textStorage release];
313   *ascent = spaceLocation.y;
314   *descent = NSHeight (usedRect) - spaceLocation.y;
315   *leading = 0;
316   descender = [nsFont descender];
317   if (- descender < *descent)
318     {
319       *leading = *descent + descender;
320       *descent = - descender;
321     }
323   return true;
326 static CFIndex
327 mac_font_shape_1 (NSFont *font, NSString *string,
328                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
329                   BOOL screen_font_p)
331   NSUInteger i;
332   CFIndex result = 0;
333   NSTextStorage *textStorage;
334   NSLayoutManager *layoutManager;
335   NSTextContainer *textContainer;
336   NSUInteger stringLength;
337   NSPoint spaceLocation;
338   NSUInteger used, numberOfGlyphs;
340   textStorage = [[NSTextStorage alloc] initWithString:string];
341   layoutManager = [[NSLayoutManager alloc] init];
342   textContainer = [[NSTextContainer alloc] init];
344   /* Append a trailing space to measure baseline position.  */
345   [textStorage appendAttributedString:([[[NSAttributedString alloc]
346                                           initWithString:@" "] autorelease])];
347   [textStorage setFont:font];
348   [textContainer setLineFragmentPadding:0];
349   [layoutManager setUsesScreenFonts:screen_font_p];
351   [layoutManager addTextContainer:textContainer];
352   [textContainer release];
353   [textStorage addLayoutManager:layoutManager];
354   [layoutManager release];
356   if (!(textStorage && layoutManager && textContainer))
357     {
358       [textStorage release];
360       return 0;
361     }
363   stringLength = [string length];
365   /* Force layout.  */
366   (void) [layoutManager glyphRangeForTextContainer:textContainer];
368   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
370   /* Remove the appended trailing space because otherwise it may
371      generate a wrong result for a right-to-left text.  */
372   [textStorage beginEditing];
373   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
374   [textStorage endEditing];
375   (void) [layoutManager glyphRangeForTextContainer:textContainer];
377   i = 0;
378   while (i < stringLength)
379     {
380       NSRange range;
381       NSFont *fontInTextStorage =
382         [textStorage attribute:NSFontAttributeName atIndex:i
383                      longestEffectiveRange:&range
384                        inRange:(NSMakeRange (0, stringLength))];
386       if (!(fontInTextStorage == font
387             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
388         break;
389       i = NSMaxRange (range);
390     }
391   if (i < stringLength)
392     /* Make the test `used <= glyph_len' below fail if textStorage
393        contained some fonts other than the specified one.  */
394     used = glyph_len + 1;
395   else
396     {
397       NSRange range = NSMakeRange (0, stringLength);
399       range = [layoutManager glyphRangeForCharacterRange:range
400                                     actualCharacterRange:NULL];
401       numberOfGlyphs = NSMaxRange (range);
402       used = numberOfGlyphs;
403       for (i = 0; i < numberOfGlyphs; i++)
404         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
405           used--;
406     }
408   if (0 < used && used <= glyph_len)
409     {
410       NSUInteger glyphIndex, prevGlyphIndex;
411       unsigned char bidiLevel;
412       NSUInteger *permutation;
413       NSRange compRange, range;
414       CGFloat totalAdvance;
416       glyphIndex = 0;
417       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
418         glyphIndex++;
420       /* For now we assume the direction is not changed within the
421          string.  */
422       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
423                                glyphs:NULL characterIndexes:NULL
424                     glyphInscriptions:NULL elasticBits:NULL
425                            bidiLevels:&bidiLevel];
426       if (bidiLevel & 1)
427         permutation = xmalloc (sizeof (NSUInteger) * used);
428       else
429         permutation = NULL;
431 #define RIGHT_TO_LEFT_P permutation
433       /* Fill the `comp_range' member of struct mac_glyph_layout, and
434          setup a permutation for right-to-left text.  */
435       compRange = NSMakeRange (0, 0);
436       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
437            range.length++)
438         {
439           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
440           NSUInteger characterIndex =
441             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
443           gl->string_index = characterIndex;
445           if (characterIndex >= NSMaxRange (compRange))
446             {
447               compRange.location = NSMaxRange (compRange);
448               do
449                 {
450                   NSRange characterRange =
451                     [string
452                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
454                   compRange.length =
455                     NSMaxRange (characterRange) - compRange.location;
456                   [layoutManager glyphRangeForCharacterRange:compRange
457                                         actualCharacterRange:&characterRange];
458                   characterIndex = NSMaxRange (characterRange) - 1;
459                 }
460               while (characterIndex >= NSMaxRange (compRange));
462               if (RIGHT_TO_LEFT_P)
463                 for (i = 0; i < range.length; i++)
464                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
466               range = NSMakeRange (NSMaxRange (range), 0);
467             }
469           gl->comp_range.location = compRange.location;
470           gl->comp_range.length = compRange.length;
472           while (++glyphIndex < numberOfGlyphs)
473             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
474               break;
475         }
476       if (RIGHT_TO_LEFT_P)
477         for (i = 0; i < range.length; i++)
478           permutation[range.location + i] = NSMaxRange (range) - i - 1;
480       /* Then fill the remaining members.  */
481       glyphIndex = prevGlyphIndex = 0;
482       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
483         glyphIndex++;
485       if (!RIGHT_TO_LEFT_P)
486         totalAdvance = 0;
487       else
488         {
489           NSUInteger nrects;
490           NSRect *glyphRects =
491             [layoutManager
492               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
493               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
494                      inTextContainer:textContainer rectCount:&nrects];
496           totalAdvance = NSMaxX (glyphRects[0]);
497         }
499       for (i = 0; i < used; i++)
500         {
501           struct mac_glyph_layout *gl;
502           NSPoint location;
503           NSUInteger nextGlyphIndex;
504           NSRange glyphRange;
505           NSRect *glyphRects;
506           NSUInteger nrects;
508           if (!RIGHT_TO_LEFT_P)
509             gl = glyph_layouts + i;
510           else
511             {
512               NSUInteger dest = permutation[i];
514               gl = glyph_layouts + dest;
515               if (i < dest)
516                 {
517                   CFIndex tmp = gl->string_index;
519                   gl->string_index = glyph_layouts[i].string_index;
520                   glyph_layouts[i].string_index = tmp;
521                 }
522             }
523           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
525           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
526           gl->baseline_delta = spaceLocation.y - location.y;
528           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
529                nextGlyphIndex++)
530             if (![layoutManager
531                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
532               break;
534           if (!RIGHT_TO_LEFT_P)
535             {
536               CGFloat maxX;
538               if (prevGlyphIndex == 0)
539                 glyphRange = NSMakeRange (0, nextGlyphIndex);
540               else
541                 glyphRange = NSMakeRange (glyphIndex,
542                                           nextGlyphIndex - glyphIndex);
543               glyphRects =
544                 [layoutManager
545                   rectArrayForGlyphRange:glyphRange
546                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
547                          inTextContainer:textContainer rectCount:&nrects];
548               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
549               gl->advance_delta = location.x - totalAdvance;
550               gl->advance = maxX - totalAdvance;
551               totalAdvance = maxX;
552             }
553           else
554             {
555               CGFloat minX;
557               if (nextGlyphIndex == numberOfGlyphs)
558                 glyphRange = NSMakeRange (prevGlyphIndex,
559                                           numberOfGlyphs - prevGlyphIndex);
560               else
561                 glyphRange = NSMakeRange (prevGlyphIndex,
562                                           glyphIndex + 1 - prevGlyphIndex);
563               glyphRects =
564                 [layoutManager
565                   rectArrayForGlyphRange:glyphRange
566                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
567                          inTextContainer:textContainer rectCount:&nrects];
568               minX = min (NSMinX (glyphRects[0]), totalAdvance);
569               gl->advance = totalAdvance - minX;
570               totalAdvance = minX;
571               gl->advance_delta = location.x - totalAdvance;
572             }
574           prevGlyphIndex = glyphIndex + 1;
575           glyphIndex = nextGlyphIndex;
576         }
578       if (RIGHT_TO_LEFT_P)
579         xfree (permutation);
581 #undef RIGHT_TO_LEFT_P
583       result = used;
584     }
585   [textStorage release];
587   return result;
590 static CFIndex
591 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
592                        struct mac_glyph_layout *glyph_layouts,
593                        CFIndex glyph_len)
595   return mac_font_shape_1 ([(NSFont *)font printerFont],
596                            (NSString *) string,
597                            glyph_layouts, glyph_len, YES);
600 static CGColorRef
601 get_cgcolor(unsigned long idx, struct frame *f)
603   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
604   [nsColor set];
605   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
606   NSInteger noc = [nsColor numberOfComponents];
607   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
608   CGColorRef cgColor;
610   [nsColor getComponents: components];
611   cgColor = CGColorCreate (colorSpace, components);
612   xfree (components);
613   return cgColor;
616 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
617   do {                                                                  \
618     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
619     CGContextSetFillColorWithColor (context, refcol_) ;                 \
620     CGColorRelease (refcol_);                                           \
621   } while (0)
622 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
623   do {                                                                  \
624     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
625     CGContextSetFillColorWithColor (context, refcol_);                  \
626     CGColorRelease (refcol_);                                           \
627   } while (0)
628 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
629   do {                                                                  \
630     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
631     CGContextSetStrokeColorWithColor (context, refcol_);                \
632     CGColorRelease (refcol_);                                           \
633   } while (0)
637 /* Mac font driver.  */
639 static struct
641   /* registry name */
642   const char *name;
643   /* characters to distinguish the charset from the others */
644   int uniquifier[6];
645   /* additional constraint by language */
646   CFStringRef lang;
647   /* set on demand */
648   CFCharacterSetRef cf_charset;
649   CFStringRef cf_charset_string;
650 } cf_charset_table[] =
651   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
652     { "iso8859-2", { 0x00A0, 0x010E }},
653     { "iso8859-3", { 0x00A0, 0x0108 }},
654     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
655     { "iso8859-5", { 0x00A0, 0x0401 }},
656     { "iso8859-6", { 0x00A0, 0x060C }},
657     { "iso8859-7", { 0x00A0, 0x0384 }},
658     { "iso8859-8", { 0x00A0, 0x05D0 }},
659     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
660     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
661     { "iso8859-11", { 0x00A0, 0x0E01 }},
662     { "iso8859-13", { 0x00A0, 0x201C }},
663     { "iso8859-14", { 0x00A0, 0x0174 }},
664     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
665     { "iso8859-16", { 0x00A0, 0x0218}},
666     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
667     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
668     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
669     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
670     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
671     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
672     { "cns11643.1992-3", { 0x201A9 }},
673     { "cns11643.1992-4", { 0x20057 }},
674     { "cns11643.1992-5", { 0x20000 }},
675     { "cns11643.1992-6", { 0x20003 }},
676     { "cns11643.1992-7", { 0x20055 }},
677     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
678     { "jisx0212.1990-0", { 0x4E44 }},
679     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
680     { "jisx0213.2000-2", { 0xFA49 }},
681     { "jisx0213.2004-1", { 0x20B9F }},
682     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
683     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
684     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
685     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
686     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
687     { "unicode-sip", { 0x20000 }},
688     { NULL }
689   };
691 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
692 static const struct
694   CFStringRef language;
695   CFStringRef font_names[3];
696 } macfont_language_default_font_names[] = {
697   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
698                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
699                     NULL }},
700   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
701                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
702                     NULL }},
703   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
704                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
705                          NULL }},
706   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
707                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
708                          NULL }},
709   { NULL }
711 #endif
713 static CGFloat macfont_antialias_threshold;
715 void
716 macfont_update_antialias_threshold (void)
718   int threshold;
719   Boolean valid_p;
721   threshold =
722     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
723                                      kCFPreferencesCurrentApplication,
724                                      &valid_p);
725   if (valid_p)
726     macfont_antialias_threshold = threshold;
729 static inline Lisp_Object
730 macfont_intern_prop_cfstring (CFStringRef cfstring)
732   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
734   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
737 static inline CFIndex
738 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
740   if (c < 0x10000)
741     {
742       unichars[0] = c;
744       return 1;
745     }
746   else
747     {
748       c -= 0x10000;
749       unichars[0] = (c >> 10) + 0xD800;
750       unichars[1] = (c & 0x3FF) + 0xDC00;
752       return 2;
753     }
756 static Boolean
757 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
758                                          FontSymbolicTraits *sym_traits)
760   SInt64 sint64_value;
762   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
763      OS X 10.6 when the value is greater than or equal to 1 << 31.  */
764   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
765     {
766       *sym_traits = (FontSymbolicTraits) sint64_value;
768       return true;
769     }
771   return false;
774 static void
775 macfont_store_descriptor_attributes (FontDescriptorRef desc,
776                                      Lisp_Object spec_or_entity)
778   CFStringRef str;
779   CFDictionaryRef dict;
780   CFNumberRef num;
781   CGFloat floatval;
783   str = mac_font_descriptor_copy_attribute (desc,
784                                             MAC_FONT_FAMILY_NAME_ATTRIBUTE);
785   if (str)
786     {
787       ASET (spec_or_entity, FONT_FAMILY_INDEX,
788             macfont_intern_prop_cfstring (str));
789       CFRelease (str);
790     }
791   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
792   if (dict)
793     {
794       struct {
795         enum font_property_index index;
796         CFStringRef trait;
797         CGPoint points[6];
798       } numeric_traits[] =
799           {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
800             {{-0.4, 50},        /* light */
801              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
802              {0, 100},          /* normal */
803              {0.24, 140},       /* (semi-bold + normal) / 2 */
804              {0.4, 200},        /* bold */
805              {CGFLOAT_MAX, CGFLOAT_MAX}}},
806            {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
807             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
808            {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
809             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
810       int i;
812       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
813         {
814           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
815           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
816             {
817               CGPoint *point = numeric_traits[i].points;
819               while (point->x < floatval)
820                 point++;
821               if (point == numeric_traits[i].points)
822                 point++;
823               else if (point->x == CGFLOAT_MAX)
824                 point--;
825               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
826                                            * ((point->y - (point - 1)->y)
827                                               / (point->x - (point - 1)->x)));
828               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
829                               make_number (lround (floatval)));
830             }
831         }
833       num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
834       if (num)
835         {
836           FontSymbolicTraits sym_traits;
837           int spacing;
839           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
840           spacing = (sym_traits & MAC_FONT_TRAIT_MONO_SPACE
841                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
842           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
843         }
845       CFRelease (dict);
846     }
847   num = mac_font_descriptor_copy_attribute (desc, MAC_FONT_SIZE_ATTRIBUTE);
848   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
849     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
850   else
851     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
852   if (num)
853     CFRelease (num);
856 static Lisp_Object
857 macfont_descriptor_entity (FontDescriptorRef desc, Lisp_Object extra,
858                            FontSymbolicTraits synth_sym_traits)
860   Lisp_Object entity;
861   CFDictionaryRef dict;
862   FontSymbolicTraits sym_traits = 0;
863   CFStringRef name;
865   entity = font_make_entity ();
867   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
868   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
870   macfont_store_descriptor_attributes (desc, entity);
872   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
873   if (dict)
874     {
875       CFNumberRef num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
877       if (num)
878         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
879       CFRelease (dict);
880     }
881   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
882     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
883   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
884   name = mac_font_descriptor_copy_attribute (desc, MAC_FONT_NAME_ATTRIBUTE);
885   font_put_extra (entity, QCfont_entity,
886                   make_save_ptr_int ((void *) name, sym_traits));
887   if (synth_sym_traits & MAC_FONT_TRAIT_ITALIC)
888     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
889                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
890   if (synth_sym_traits & MAC_FONT_TRAIT_BOLD)
891     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
892                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
893   if (synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
894     ASET (entity, FONT_SPACING_INDEX,
895           make_number (FONT_SPACING_SYNTHETIC_MONO));
897   return entity;
900 /* Cache for font family name symbols vs CFStrings.  A value of nil
901 means the cache has been invalidated.  Otherwise the value is a Lisp
902 hash table whose keys are symbols and the value for a key is either
903 nil (no corresponding family name) or a Lisp save value wrapping the
904 corresponding family name in CFString.  */
906 static Lisp_Object macfont_family_cache;
908 static void
909 macfont_invalidate_family_cache (void)
911   if (HASH_TABLE_P (macfont_family_cache))
912     {
913       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
914       ptrdiff_t i, size = HASH_TABLE_SIZE (h);
916       for (i = 0; i < size; ++i)
917         if (!NILP (HASH_HASH (h, i)))
918           {
919             Lisp_Object value = HASH_VALUE (h, i);
921             if (SAVE_VALUEP (value))
922               CFRelease (XSAVE_POINTER (value, 0));
923           }
924       macfont_family_cache = Qnil;
925     }
928 static bool
929 macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
931   if (HASH_TABLE_P (macfont_family_cache))
932     {
933       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
934       ptrdiff_t i = hash_lookup (h, symbol, NULL);
936       if (i >= 0)
937         {
938           Lisp_Object value = HASH_VALUE (h, i);
940           *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
942           return true;
943         }
944     }
946   return false;
949 static void
950 macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
952   struct Lisp_Hash_Table *h;
953   ptrdiff_t i;
954   EMACS_UINT hash;
955   Lisp_Object value;
957   if (!HASH_TABLE_P (macfont_family_cache))
958     {
959       Lisp_Object args[2];
961       args[0] = QCtest;
962       args[1] = Qeq;
963       macfont_family_cache = Fmake_hash_table (2, args);
964     }
966   h = XHASH_TABLE (macfont_family_cache);
967   i = hash_lookup (h, symbol, &hash);
968   value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
969   if (i >= 0)
970     {
971       Lisp_Object old_value = HASH_VALUE (h, i);
973       if (SAVE_VALUEP (old_value))
974         CFRelease (XSAVE_POINTER (old_value, 0));
975       set_hash_value_slot (h, i, value);
976     }
977   else
978     hash_put (h, symbol, value, hash);
981 /* Cache of all the available font family names except "LastResort"
982 and those start with ".".  NULL means the cache has been invalidated.
983 Otherwise, the value is CFArray of CFStrings and the elements are
984 sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
985 OS X 10.6 and later).  */
987 static CFArrayRef macfont_available_families_cache = NULL;
989 static void
990 macfont_invalidate_available_families_cache (void)
992   if (macfont_available_families_cache)
993     {
994       CFRelease (macfont_available_families_cache);
995       macfont_available_families_cache = NULL;
996     }
999 static void
1000 macfont_handle_font_change_notification (CFNotificationCenterRef center,
1001                                          void *observer,
1002                                          CFStringRef name, const void *object,
1003                                          CFDictionaryRef userInfo)
1005   macfont_invalidate_family_cache ();
1006   macfont_invalidate_available_families_cache ();
1009 static void
1010 macfont_init_font_change_handler (void)
1012   static bool initialized = false;
1014   if (initialized)
1015     return;
1017   initialized = true;
1018   CFNotificationCenterAddObserver
1019     (CFNotificationCenterGetLocalCenter (), NULL,
1020      macfont_handle_font_change_notification,
1021      kCTFontManagerRegisteredFontsChangedNotification,
1022      NULL, CFNotificationSuspensionBehaviorCoalesce);
1025 static CFArrayRef
1026 macfont_copy_available_families_cache (void)
1028   macfont_init_font_change_handler ();
1030   if (macfont_available_families_cache == NULL)
1031     macfont_available_families_cache = mac_font_create_available_families ();
1033   return (macfont_available_families_cache
1034           ? CFRetain (macfont_available_families_cache) : NULL);
1037 static CFStringRef
1038 macfont_create_family_with_symbol (Lisp_Object symbol)
1040   CFStringRef result = NULL, family_name;
1041   CFComparatorFunction family_name_comparator;
1043   if (macfont_get_family_cache_if_present (symbol, &result))
1044     return result ? CFRetain (result) : NULL;
1046   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1047   if (family_name == NULL)
1048     return NULL;
1050     {
1051       family_name_comparator = CTFontManagerCompareFontFamilyNames;
1052     }
1054   if ((*family_name_comparator) (family_name, CFSTR ("LastResort"), NULL)
1055       == kCFCompareEqualTo)
1056     result = CFSTR ("LastResort");
1057   else
1058     {
1059       CFIndex i, count;
1060       CFArrayRef families = macfont_copy_available_families_cache ();
1062       if (families)
1063         {
1064           count = CFArrayGetCount (families);
1065           i = CFArrayBSearchValues (families, CFRangeMake (0, count),
1066                                     (const void *) family_name,
1067                                     family_name_comparator, NULL);
1068           if (i < count)
1069             {
1070               CFStringRef name = CFArrayGetValueAtIndex (families, i);
1072               if ((*family_name_comparator) (name, family_name, NULL)
1073                   == kCFCompareEqualTo)
1074                 result = CFRetain (name);
1075             }
1076           CFRelease (families);
1077         }
1078     }
1080   CFRelease (family_name);
1082   macfont_set_family_cache (symbol, result);
1084   return result;
1087 #define WIDTH_FRAC_BITS         (4)
1088 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1090 struct macfont_metrics
1092   unsigned char lbearing_low, rbearing_low;
1093   signed lbearing_high : 4, rbearing_high : 4;
1094   unsigned char ascent_low, descent_low;
1095   signed ascent_high : 4, descent_high : 4;
1097   /* These two members are used for fixed-point representation of
1098      glyph width.  The `width_int' member is an integer that is
1099      closest to the width.  The `width_frac' member is the fractional
1100      adjustment representing a value in [-.5, .5], multiplied by
1101      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1102      the advance delta for centering instead of the glyph width.  */
1103   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1106 #define METRICS_VALUE(metrics, member)                          \
1107   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1108 #define METRICS_SET_VALUE(metrics, member, value)                   \
1109   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
1110     (metrics)->member##_high = tmp >> 8;} while (0)
1112 enum metrics_status
1114   METRICS_INVALID = -1,    /* metrics entry is invalid */
1115   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1118 #define METRICS_STATUS(metrics)                                         \
1119   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1120 #define METRICS_SET_STATUS(metrics, status)                     \
1121   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1122     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1124 #define METRICS_NCOLS_PER_ROW   (128)
1125 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1126 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1128 static int
1129 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1130                        struct font_metrics *metrics, CGFloat *advance_delta,
1131                        int force_integral_p)
1133   struct macfont_info *macfont_info = (struct macfont_info *) font;
1134   FontRef macfont = macfont_info->macfont;
1135   int row, col;
1136   struct macfont_metrics *cache;
1137   int width;
1139   row = glyph / METRICS_NCOLS_PER_ROW;
1140   col = glyph % METRICS_NCOLS_PER_ROW;
1141   if (row >= macfont_info->metrics_nrows)
1142     {
1143       macfont_info->metrics =
1144         xrealloc (macfont_info->metrics,
1145                   sizeof (struct macfont_metrics *) * (row + 1));
1146       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1147               (sizeof (struct macfont_metrics *)
1148                * (row + 1 - macfont_info->metrics_nrows)));
1149       macfont_info->metrics_nrows = row + 1;
1150     }
1151   if (macfont_info->metrics[row] == NULL)
1152     {
1153       struct macfont_metrics *new;
1154       int i;
1156       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1157       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1158         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1159       macfont_info->metrics[row] = new;
1160     }
1161   cache = macfont_info->metrics[row] + col;
1163   if (METRICS_STATUS (cache) == METRICS_INVALID)
1164     {
1165       CGFloat fwidth;
1167       if (macfont_info->screen_font)
1168         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1169       else
1170         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1172       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1173          advance delta value.  */
1174       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1175         fwidth = (font->pixel_size - fwidth) / 2;
1176       cache->width_int = lround (fwidth);
1177       cache->width_frac = lround ((fwidth - cache->width_int)
1178                                   * WIDTH_FRAC_SCALE);
1179       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1180     }
1181   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1182     width = font->pixel_size;
1183   else
1184     width = cache->width_int;
1186   if (metrics)
1187     {
1188       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1189         {
1190           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1192           if (macfont_info->synthetic_italic_p)
1193             {
1194               /* We assume the members a, b, c, and d in
1195                  synthetic_italic_atfm are non-negative.  */
1196               bounds.origin =
1197                 CGPointApplyAffineTransform (bounds.origin,
1198                                              synthetic_italic_atfm);
1199               bounds.size =
1200                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1201             }
1202           if (macfont_info->synthetic_bold_p && ! force_integral_p)
1203             {
1204               CGFloat d =
1205                 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1207                 bounds = CGRectInset (bounds, d, d);
1208             }
1209           switch (macfont_info->spacing)
1210             {
1211             case MACFONT_SPACING_PROPORTIONAL:
1212               bounds.origin.x += - (cache->width_frac
1213                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1214               break;
1215             case MACFONT_SPACING_MONO:
1216               break;
1217             case MACFONT_SPACING_SYNTHETIC_MONO:
1218               bounds.origin.x += (cache->width_int
1219                                   + (cache->width_frac
1220                                      / (CGFloat) WIDTH_FRAC_SCALE));
1221               break;
1222             }
1223           if (bounds.size.width > 0)
1224             {
1225               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1226               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1227                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1228             }
1229           bounds = CGRectIntegral (bounds);
1230           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1231           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1232           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1233           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1234         }
1235       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1236       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1237       metrics->width = width;
1238       metrics->ascent = METRICS_VALUE (cache, ascent);
1239       metrics->descent = METRICS_VALUE (cache, descent);
1240     }
1242   if (advance_delta)
1243     {
1244       switch (macfont_info->spacing)
1245         {
1246         case MACFONT_SPACING_PROPORTIONAL:
1247           *advance_delta = (force_integral_p ? 0
1248                             : - (cache->width_frac
1249                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1250           break;
1251         case MACFONT_SPACING_MONO:
1252           *advance_delta = 0;
1253           break;
1254         case MACFONT_SPACING_SYNTHETIC_MONO:
1255           *advance_delta = (force_integral_p ? cache->width_int
1256                             : (cache->width_int
1257                                + (cache->width_frac
1258                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1259           break;
1260         }
1261     }
1263   return width;
1266 static CFMutableDictionaryRef macfont_cache_dictionary;
1268 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1269    equal to the number of rows that are invalid as BMP (i.e., from
1270    U+D800 to U+DFFF).  */
1271 #define ROW_PERM_OFFSET (8)
1273 /* The number of glyphs that can be stored in a value for a single
1274    entry of CFDictionary.  */
1275 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1277 struct macfont_cache
1279   int reference_count;
1280   CFCharacterSetRef cf_charset;
1281   struct {
1282     /* The cached glyph for a BMP character c is stored in
1283        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1284        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1285     unsigned char row_nkeys_or_perm[256];
1286     CGGlyph **matrix;
1288     /* Number of rows for which the BMP cache is allocated so far.
1289        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1290     int nrows;
1292     /* The cached glyph for a character c is stored as the (c %
1293        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1294        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1295        not stored here if row_nkeys_or_perm[c / 256] >=
1296        ROW_PERM_OFFSET.  */
1297     CFMutableDictionaryRef dictionary;
1298   } glyph;
1300   struct {
1301     /* UVS (Unicode Variation Sequence) subtable data, which is of
1302        type CFDataRef if available.  NULL means it is not initialized
1303        yet.  kCFNull means the subtable is not found and there is no
1304        suitable fallback table for this font.  */
1305     CFTypeRef table;
1307     /* Character collection specifying the destination of the mapping
1308        provided by `table' above.  If `table' is obtained from the UVS
1309        subtable in the font cmap table, then the value of this member
1310        should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING.  */
1311     CharacterCollection collection;
1312   } uvs;
1315 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1316 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1317 static void macfont_release_cache (struct macfont_cache *);
1318 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1319 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1320 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1321 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1322                                           CharacterCollection, CGFontIndex);
1323 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1325 static struct macfont_cache *
1326 macfont_lookup_cache (CFStringRef key)
1328   struct macfont_cache *cache;
1330   if (macfont_cache_dictionary == NULL)
1331     {
1332       macfont_cache_dictionary =
1333         CFDictionaryCreateMutable (NULL, 0,
1334                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1335       cache = NULL;
1336     }
1337   else
1338     cache = ((struct macfont_cache *)
1339              CFDictionaryGetValue (macfont_cache_dictionary, key));
1341   if (cache == NULL)
1342     {
1343       FontRef macfont = mac_font_create_with_name (key, 0);
1345       if (macfont)
1346         {
1347           cache = xzalloc (sizeof (struct macfont_cache));
1348           /* Treat the LastResort font as if it contained glyphs for
1349              all characters.  This may look too rough, but neither
1350              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1351              for this font is correct for non-BMP characters on Mac OS
1352              X 10.5, anyway.  */
1353           if (CFEqual (key, CFSTR ("LastResort")))
1354             {
1355               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1357               cache->cf_charset =
1358                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1359             }
1360           if (cache->cf_charset == NULL)
1361             cache->cf_charset = mac_font_copy_character_set (macfont);
1362           CFDictionaryAddValue (macfont_cache_dictionary, key,
1363                                 (const void *) cache);
1364           CFRelease (macfont);
1365         }
1366     }
1368   return cache;
1371 static struct macfont_cache *
1372 macfont_retain_cache (struct macfont_cache *cache)
1374   cache->reference_count++;
1376   return cache;
1379 static void
1380 macfont_release_cache (struct macfont_cache *cache)
1382   if (--cache->reference_count == 0)
1383     {
1384       int i;
1386       for (i = 0; i < cache->glyph.nrows; i++)
1387         xfree (cache->glyph.matrix[i]);
1388       xfree (cache->glyph.matrix);
1389       if (cache->glyph.dictionary)
1390         CFRelease (cache->glyph.dictionary);
1391       memset (&cache->glyph, 0, sizeof (cache->glyph));
1392       if (cache->uvs.table)
1393         CFRelease (cache->uvs.table);
1394       memset (&cache->uvs, 0, sizeof (cache->uvs));
1395     }
1398 static CFCharacterSetRef
1399 macfont_get_cf_charset (struct font *font)
1401   struct macfont_info *macfont_info = (struct macfont_info *) font;
1403   return macfont_info->cache->cf_charset;
1406 static CFCharacterSetRef
1407 macfont_get_cf_charset_for_name (CFStringRef name)
1409   struct macfont_cache *cache = macfont_lookup_cache (name);
1411   return cache->cf_charset;
1414 static CGGlyph
1415 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1417   struct macfont_info *macfont_info = (struct macfont_info *) font;
1418   FontRef macfont = macfont_info->macfont;
1419   struct macfont_cache *cache = macfont_info->cache;
1421   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1422     {
1423       int row = c / 256;
1424       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1426       if (nkeys_or_perm < ROW_PERM_OFFSET)
1427         {
1428           UniChar unichars[256], ch;
1429           CGGlyph *glyphs;
1430           int i, len;
1431           int nrows;
1432           dispatch_queue_t queue;
1433           dispatch_group_t group = NULL;
1435           if (row != 0)
1436             {
1437               CFMutableDictionaryRef dictionary;
1438               uintptr_t key, value;
1439               int nshifts;
1440               CGGlyph glyph;
1442               if (cache->glyph.dictionary == NULL)
1443                 cache->glyph.dictionary =
1444                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1445               dictionary = cache->glyph.dictionary;
1446               key = c / NGLYPHS_IN_VALUE;
1447               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1448               value = ((uintptr_t)
1449                        CFDictionaryGetValue (dictionary, (const void *) key));
1450               glyph = (value >> nshifts);
1451               if (glyph)
1452                 return glyph;
1454               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1455                 {
1456                   ch = c;
1457                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1458                                                            &glyph, 1)
1459                       || glyph == 0)
1460                     glyph = kCGFontIndexInvalid;
1462                   if (value == 0)
1463                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1464                   value |= ((uintptr_t) glyph << nshifts);
1465                   CFDictionarySetValue (dictionary, (const void *) key,
1466                                         (const void *) value);
1468                   return glyph;
1469                 }
1471               queue =
1472                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1473               group = dispatch_group_create ();
1474               dispatch_group_async (group, queue, ^{
1475                   int nkeys;
1476                   uintptr_t key;
1477                   nkeys = nkeys_or_perm;
1478                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1479                     if (CFDictionaryContainsKey (dictionary,
1480                                                  (const void *) key))
1481                       {
1482                         CFDictionaryRemoveValue (dictionary,
1483                                                  (const void *) key);
1484                         if (--nkeys == 0)
1485                           break;
1486                       }
1487                 });
1488             }
1490           len = 0;
1491           for (i = 0; i < 256; i++)
1492             {
1493               ch = row * 256 + i;
1494               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1495                 unichars[len++] = ch;
1496             }
1498           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1499           if (len > 0)
1500             {
1501               mac_font_get_glyphs_for_characters (macfont, unichars,
1502                                                   glyphs, len);
1503               while (i > len)
1504                 {
1505                   int next = unichars[len - 1] % 256;
1507                   while (--i > next)
1508                     glyphs[i] = kCGFontIndexInvalid;
1510                   len--;
1511                   glyphs[i] = glyphs[len];
1512                   if (len == 0)
1513                     break;
1514                 }
1515             }
1516           if (i > len)
1517             while (i-- > 0)
1518               glyphs[i] = kCGFontIndexInvalid;
1520           nrows = cache->glyph.nrows;
1521           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1522           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1523           nrows++;
1524           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1525                                           sizeof (CGGlyph *) * nrows);
1526           cache->glyph.matrix[nrows - 1] = glyphs;
1527           cache->glyph.nrows = nrows;
1529           if (group)
1530             {
1531               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1532               dispatch_release (group);
1533             }
1534         }
1536       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1537     }
1538   else
1539     {
1540       uintptr_t key, value;
1541       int nshifts;
1542       CGGlyph glyph;
1544       if (cache->glyph.dictionary == NULL)
1545         cache->glyph.dictionary =
1546           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1547       key = c / NGLYPHS_IN_VALUE;
1548       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1549       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1550                                                 (const void *) key);
1551       glyph = (value >> nshifts);
1552       if (glyph == 0)
1553         {
1554           UniChar unichars[2];
1555           CGGlyph glyphs[2];
1556           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1558           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1559                                                   count))
1560             glyph = glyphs[0];
1561           if (glyph == 0)
1562             glyph = kCGFontIndexInvalid;
1564           value |= ((uintptr_t) glyph << nshifts);
1565           CFDictionarySetValue (cache->glyph.dictionary,
1566                                 (const void *) key, (const void *) value);
1567         }
1569       return glyph;
1570     }
1573 static CGGlyph
1574 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1575                            CGFontIndex cid)
1577   struct macfont_info *macfont_info = (struct macfont_info *) font;
1578   FontRef macfont = macfont_info->macfont;
1580   /* Cache it? */
1581   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1584 static CFDataRef
1585 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1587   struct macfont_info *macfont_info = (struct macfont_info *) font;
1588   FontRef macfont = macfont_info->macfont;
1589   struct macfont_cache *cache = macfont_info->cache;
1590   CFDataRef result = NULL;
1592   if (cache->uvs.table == NULL)
1593     {
1594       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1595       CharacterCollection uvs_collection =
1596         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1598       if (uvs_table == NULL
1599           && mac_font_get_glyph_for_cid (macfont,
1600                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1601                                          6480) != kCGFontIndexInvalid)
1602         {
1603           /* If the glyph for U+4E55 is accessible via its CID 6480,
1604              then we use the Adobe-Japan1 UVS table, which maps a
1605              variation sequence to a CID, as a fallback.  */
1606           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1608           if (mac_uvs_table_adobe_japan1 == NULL)
1609             mac_uvs_table_adobe_japan1 =
1610               CFDataCreateWithBytesNoCopy (NULL,
1611                                            mac_uvs_table_adobe_japan1_bytes,
1612                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1613                                            kCFAllocatorNull);
1614           if (mac_uvs_table_adobe_japan1)
1615             {
1616               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1617               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1618             }
1619         }
1620       if (uvs_table == NULL)
1621         cache->uvs.table = kCFNull;
1622       else
1623         cache->uvs.table = uvs_table;
1624       cache->uvs.collection = uvs_collection;
1625     }
1627   if (cache->uvs.table != kCFNull)
1628     {
1629       result = cache->uvs.table;
1630       *collection = cache->uvs.collection;
1631     }
1633   return result;
1636 static Lisp_Object macfont_get_cache (struct frame *);
1637 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1638 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1639 static Lisp_Object macfont_list_family (struct frame *);
1640 static void macfont_free_entity (Lisp_Object);
1641 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1642 static void macfont_close (struct font *);
1643 static int macfont_has_char (Lisp_Object, int);
1644 static unsigned macfont_encode_char (struct font *, int);
1645 static void macfont_text_extents (struct font *, unsigned int *, int,
1646                                   struct font_metrics *);
1647 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1648 static Lisp_Object macfont_shape (Lisp_Object);
1649 static int macfont_variation_glyphs (struct font *, int c,
1650                                      unsigned variations[256]);
1651 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1653 static struct font_driver macfont_driver =
1654   {
1655     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1656     0,                          /* case insensitive */
1657     macfont_get_cache,
1658     macfont_list,
1659     macfont_match,
1660     macfont_list_family,
1661     macfont_free_entity,
1662     macfont_open,
1663     macfont_close,
1664     NULL,                       /* prepare_face */
1665     NULL,                       /* done_face */
1666     macfont_has_char,
1667     macfont_encode_char,
1668     macfont_text_extents,
1669     macfont_draw,
1670     NULL,                       /* get_bitmap */
1671     NULL,                       /* free_bitmap */
1672     NULL,                       /* anchor_point */
1673     NULL,                       /* otf_capability */
1674     NULL,                       /* otf_drive */
1675     NULL,                       /* start_for_frame */
1676     NULL,                       /* end_for_frame */
1677     macfont_shape,
1678     NULL,                       /* check */
1679     macfont_variation_glyphs,
1680     macfont_filter_properties,
1681   };
1683 static Lisp_Object
1684 macfont_get_cache (struct frame * f)
1686   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1688   return (dpyinfo->name_list_element);
1691 static int
1692 macfont_get_charset (Lisp_Object registry)
1694   char *str = SSDATA (SYMBOL_NAME (registry));
1695   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1696   Lisp_Object regexp;
1697   int i, j;
1699   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1700     {
1701       if (str[i] == '.')
1702         re[j++] = '\\';
1703       else if (str[i] == '*')
1704         re[j++] = '.';
1705       re[j] = str[i];
1706       if (re[j] == '?')
1707         re[j] = '.';
1708     }
1709   re[j] = '\0';
1710   regexp = make_unibyte_string (re, j);
1711   for (i = 0; cf_charset_table[i].name; i++)
1712     if (fast_c_string_match_ignore_case
1713         (regexp, cf_charset_table[i].name,
1714          strlen (cf_charset_table[i].name)) >= 0)
1715       break;
1716   if (! cf_charset_table[i].name)
1717     return -1;
1718   if (! cf_charset_table[i].cf_charset)
1719     {
1720       int *uniquifier = cf_charset_table[i].uniquifier;
1721       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1722       CFIndex count = 0;
1723       CFStringRef string;
1724       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1726       if (! charset)
1727         return -1;
1728       for (j = 0; uniquifier[j]; j++)
1729         {
1730           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1731                                                         unichars + count);
1732           CFCharacterSetAddCharactersInRange (charset,
1733                                               CFRangeMake (uniquifier[j], 1));
1734         }
1736       string = CFStringCreateWithCharacters (NULL, unichars, count);
1737       if (! string)
1738         {
1739           CFRelease (charset);
1740           return -1;
1741         }
1742       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1743                                                                  charset);
1744       CFRelease (charset);
1745       /* CFCharacterSetCreateWithCharactersInString does not handle
1746          surrogate pairs properly as of Mac OS X 10.5.  */
1747       cf_charset_table[i].cf_charset_string = string;
1748     }
1749   return i;
1752 struct OpenTypeSpec
1754   Lisp_Object script;
1755   unsigned int script_tag, langsys_tag;
1756   int nfeatures[2];
1757   unsigned int *features[2];
1760 #define OTF_SYM_TAG(SYM, TAG)                               \
1761   do {                                                      \
1762     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1763     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1764   } while (0)
1766 #define OTF_TAG_STR(TAG, P)                     \
1767   do {                                          \
1768     (P)[0] = (char) (TAG >> 24);                \
1769     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1770     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1771     (P)[3] = (char) (TAG & 0xFF);               \
1772     (P)[4] = '\0';                              \
1773   } while (0)
1775 static struct OpenTypeSpec *
1776 macfont_get_open_type_spec (Lisp_Object otf_spec)
1778   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1779   Lisp_Object val;
1780   int i, j;
1781   bool negative;
1783   if (! spec)
1784     return NULL;
1785   spec->script = XCAR (otf_spec);
1786   if (! NILP (spec->script))
1787     {
1788       OTF_SYM_TAG (spec->script, spec->script_tag);
1789       val = assq_no_quit (spec->script, Votf_script_alist);
1790       if (CONSP (val) && SYMBOLP (XCDR (val)))
1791         spec->script = XCDR (val);
1792       else
1793         spec->script = Qnil;
1794     }
1795   else
1796     spec->script_tag = 0x44464C54;      /* "DFLT" */
1797   otf_spec = XCDR (otf_spec);
1798   spec->langsys_tag = 0;
1799   if (! NILP (otf_spec))
1800     {
1801       val = XCAR (otf_spec);
1802       if (! NILP (val))
1803         OTF_SYM_TAG (val, spec->langsys_tag);
1804       otf_spec = XCDR (otf_spec);
1805     }
1806   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1807   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1808     {
1809       Lisp_Object len;
1811       val = XCAR (otf_spec);
1812       if (NILP (val))
1813         continue;
1814       len = Flength (val);
1815       spec->features[i] =
1816         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1817          ? 0
1818          : malloc (XINT (len) * sizeof *spec->features[i]));
1819       if (! spec->features[i])
1820         {
1821           if (i > 0 && spec->features[0])
1822             free (spec->features[0]);
1823           free (spec);
1824           return NULL;
1825         }
1826       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1827         {
1828           if (NILP (XCAR (val)))
1829             negative = 1;
1830           else
1831             {
1832               unsigned int tag;
1834               OTF_SYM_TAG (XCAR (val), tag);
1835               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1836             }
1837         }
1838       spec->nfeatures[i] = j;
1839     }
1840   return spec;
1843 static CFMutableDictionaryRef
1844 macfont_create_attributes_with_spec (Lisp_Object spec)
1846   Lisp_Object tmp, extra;
1847   CFMutableArrayRef langarray = NULL;
1848   CFCharacterSetRef charset = NULL;
1849   CFStringRef charset_string = NULL;
1850   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1851   Lisp_Object script = Qnil;
1852   Lisp_Object registry;
1853   int cf_charset_idx, i;
1854   struct OpenTypeSpec *otspec = NULL;
1855   struct {
1856     enum font_property_index index;
1857     CFStringRef trait;
1858     CGPoint points[6];
1859   } numeric_traits[] =
1860       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1861         {{-0.4, 50},            /* light */
1862          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1863          {0, 100},              /* normal */
1864          {0.24, 140},           /* (semi-bold + normal) / 2 */
1865          {0.4, 200},            /* bold */
1866          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1867        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1868         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1869        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1870         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1872   registry = AREF (spec, FONT_REGISTRY_INDEX);
1873   if (NILP (registry)
1874       || EQ (registry, Qascii_0)
1875       || EQ (registry, Qiso10646_1)
1876       || EQ (registry, Qunicode_bmp))
1877     cf_charset_idx = -1;
1878   else
1879     {
1880       CFStringRef lang;
1882       cf_charset_idx = macfont_get_charset (registry);
1883       if (cf_charset_idx < 0)
1884         goto err;
1885       charset = cf_charset_table[cf_charset_idx].cf_charset;
1886       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1887       lang = cf_charset_table[cf_charset_idx].lang;
1888       if (lang)
1889         {
1890           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1891           if (! langarray)
1892             goto err;
1893           CFArrayAppendValue (langarray, lang);
1894         }
1895     }
1897   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1898        CONSP (extra); extra = XCDR (extra))
1899     {
1900       Lisp_Object key, val;
1902       tmp = XCAR (extra);
1903       key = XCAR (tmp), val = XCDR (tmp);
1904       if (EQ (key, QClang))
1905         {
1906           if (! langarray)
1907             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1908           if (! langarray)
1909             goto err;
1910           if (SYMBOLP (val))
1911             val = list1 (val);
1912           for (; CONSP (val); val = XCDR (val))
1913             if (SYMBOLP (XCAR (val)))
1914               {
1915                 CFStringRef lang =
1916                   cfstring_create_with_string_noencode (SYMBOL_NAME
1917                                                         (XCAR (val)));
1919                 if (lang == NULL)
1920                   goto err;
1921                 CFArrayAppendValue (langarray, lang);
1922                 CFRelease (lang);
1923               }
1924         }
1925       else if (EQ (key, QCotf))
1926         {
1927           otspec = macfont_get_open_type_spec (val);
1928           if (! otspec)
1929             goto err;
1930           script = otspec->script;
1931         }
1932       else if (EQ (key, QCscript))
1933         script = val;
1934     }
1936   if (! NILP (script) && ! charset)
1937     {
1938       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1940       if (CONSP (chars) && CONSP (CDR (chars)))
1941         {
1942           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1943           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1945           if (! string || !cs)
1946             {
1947               if (string)
1948                 CFRelease (string);
1949               else if (cs)
1950                 CFRelease (cs);
1951               goto err;
1952             }
1953           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1954             if (CHARACTERP (XCAR (chars)))
1955               {
1956                 UniChar unichars[2];
1957                 CFIndex count =
1958                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1959                                                        unichars);
1960                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1962                 CFStringAppendCharacters (string, unichars, count);
1963                 CFCharacterSetAddCharactersInRange (cs, range);
1964               }
1965           charset = cs;
1966           /* CFCharacterSetCreateWithCharactersInString does not
1967              handle surrogate pairs properly as of Mac OS X 10.5.  */
1968           charset_string = string;
1969         }
1970     }
1972   attributes = CFDictionaryCreateMutable (NULL, 0,
1973                                           &kCFTypeDictionaryKeyCallBacks,
1974                                           &kCFTypeDictionaryValueCallBacks);
1975   if (! attributes)
1976     goto err;
1978   tmp = AREF (spec, FONT_FAMILY_INDEX);
1979   if (SYMBOLP (tmp) && ! NILP (tmp))
1980     {
1981       CFStringRef family = macfont_create_family_with_symbol (tmp);
1983       if (! family)
1984         goto err;
1985       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1986                             family);
1987       CFRelease (family);
1988     }
1990   traits = CFDictionaryCreateMutable (NULL, 4,
1991                                       &kCFTypeDictionaryKeyCallBacks,
1992                                       &kCFTypeDictionaryValueCallBacks);
1993   if (! traits)
1994     goto err;
1996   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1997     {
1998       tmp = AREF (spec, numeric_traits[i].index);
1999       if (INTEGERP (tmp))
2000         {
2001           CGPoint *point = numeric_traits[i].points;
2002           CGFloat floatval = (XINT (tmp) >> 8); // XXX
2003           CFNumberRef num;
2005           while (point->y < floatval)
2006             point++;
2007           if (point == numeric_traits[i].points)
2008             point++;
2009           else if (point->y == CGFLOAT_MAX)
2010             point--;
2011           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
2012                                        * ((point->x - (point - 1)->x)
2013                                           / (point->y - (point - 1)->y)));
2014           if (floatval > 1.0)
2015             floatval = 1.0;
2016           else if (floatval < -1.0)
2017             floatval = -1.0;
2018           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2019           if (! num)
2020             goto err;
2021           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2022           CFRelease (num);
2023         }
2024     }
2025   if (CFDictionaryGetCount (traits))
2026     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
2028   if (charset)
2029     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
2030                           charset);
2031   if (charset_string)
2032     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2033                           charset_string);
2034   if (langarray)
2035     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
2037   goto finish;
2039  err:
2040   if (attributes)
2041     {
2042       CFRelease (attributes);
2043       attributes = NULL;
2044     }
2046  finish:
2047   if (langarray) CFRelease (langarray);
2048   if (charset && cf_charset_idx < 0) CFRelease (charset);
2049   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2050   if (traits) CFRelease (traits);
2051   if (otspec)
2052     {
2053       if (otspec->nfeatures[0] > 0)
2054         free (otspec->features[0]);
2055       if (otspec->nfeatures[1] > 0)
2056         free (otspec->features[1]);
2057       free (otspec);
2058     }
2060   return attributes;
2063 static Boolean
2064 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
2065                                           CFCharacterSetRef charset,
2066                                           Lisp_Object chars,
2067                                           CFArrayRef languages)
2069   Boolean result = true;
2071   if (charset || VECTORP (chars))
2072     {
2073       CFCharacterSetRef desc_charset =
2074         mac_font_descriptor_copy_attribute (desc,
2075                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2077       if (desc_charset == NULL)
2078         result = false;
2079       else
2080         {
2081           if (charset)
2082             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2083           else                  /* VECTORP (chars) */
2084             {
2085               ptrdiff_t j;
2087               for (j = 0; j < ASIZE (chars); j++)
2088                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2089                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2090                                                             XFASTINT (AREF (chars, j))))
2091                   break;
2092               if (j == ASIZE (chars))
2093                 result = false;
2094             }
2095           CFRelease (desc_charset);
2096         }
2097     }
2098   if (result && languages)
2099     result = mac_font_descriptor_supports_languages (desc, languages);
2101   return result;
2104 static int
2105 macfont_traits_distance (FontSymbolicTraits sym_traits1,
2106                          FontSymbolicTraits sym_traits2)
2108   FontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2109   int distance = 0;
2111   /* We prefer synthetic bold of italic to synthetic italic of bold
2112      when both bold and italic are available but bold-italic is not
2113      available.  */
2114   if (diff & MAC_FONT_TRAIT_BOLD)
2115     distance |= (1 << 0);
2116   if (diff & MAC_FONT_TRAIT_ITALIC)
2117     distance |= (1 << 1);
2118   if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2119     distance |= (1 << 2);
2121   return distance;
2124 static Boolean
2125 macfont_closest_traits_index_p (CFArrayRef traits_array,
2126                                 FontSymbolicTraits target,
2127                                 CFIndex index)
2129   CFIndex i, count = CFArrayGetCount (traits_array);
2130   FontSymbolicTraits traits;
2131   int my_distance;
2133   traits = ((FontSymbolicTraits) (uintptr_t)
2134             CFArrayGetValueAtIndex (traits_array, index));
2135   my_distance = macfont_traits_distance (target, traits);
2137   for (i = 0; i < count; i++)
2138     if (i != index)
2139       {
2140         traits = ((FontSymbolicTraits) (uintptr_t)
2141                   CFArrayGetValueAtIndex (traits_array, i));
2142         if (macfont_traits_distance (target, traits) < my_distance)
2143           return false;
2144       }
2146   return true;
2149 static Lisp_Object
2150 macfont_list (struct frame *f, Lisp_Object spec)
2152   Lisp_Object val = Qnil, family, extra;
2153   int i, n;
2154   CFStringRef family_name = NULL;
2155   CFMutableDictionaryRef attributes = NULL, traits;
2156   Lisp_Object chars = Qnil;
2157   int spacing = -1;
2158   FontSymbolicTraits synth_sym_traits = 0;
2159   CFArrayRef families;
2160   CFIndex families_count;
2161   CFCharacterSetRef charset = NULL;
2162   CFArrayRef languages = NULL;
2164   block_input ();
2166   family = AREF (spec, FONT_FAMILY_INDEX);
2167   if (! NILP (family))
2168     {
2169       family_name = macfont_create_family_with_symbol (family);
2170       if (family_name == NULL)
2171         goto finish;
2172     }
2174   attributes = macfont_create_attributes_with_spec (spec);
2175   if (! attributes)
2176     goto finish;
2178   languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2180   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2181     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2183   traits = ((CFMutableDictionaryRef)
2184             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2186   n = FONT_SLANT_NUMERIC (spec);
2187   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2188     {
2189       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2190       if (traits)
2191         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2192     }
2194   n = FONT_WEIGHT_NUMERIC (spec);
2195   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2196     {
2197       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2198       if (traits)
2199         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2200     }
2202   if (languages
2203       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2204     {
2205       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2207       if (CFStringHasPrefix (language, CFSTR ("ja"))
2208           || CFStringHasPrefix (language, CFSTR ("ko"))
2209           || CFStringHasPrefix (language, CFSTR ("zh")))
2210         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2211     }
2213   /* Create array of families.  */
2214   if (family_name)
2215     families = CFArrayCreate (NULL, (const void **) &family_name,
2216                               1, &kCFTypeArrayCallBacks);
2217   else
2218     {
2219       CFStringRef pref_family;
2220       CFIndex families_count, pref_family_index = -1;
2222       families = macfont_copy_available_families_cache ();
2223       if (families == NULL)
2224         goto err;
2226       families_count = CFArrayGetCount (families);
2228       /* Move preferred family to the front if exists.  */
2229       pref_family =
2230         mac_font_create_preferred_family_for_attributes (attributes);
2231       if (pref_family)
2232         {
2233           pref_family_index =
2234             CFArrayGetFirstIndexOfValue (families,
2235                                          CFRangeMake (0, families_count),
2236                                          pref_family);
2237           CFRelease (pref_family);
2238         }
2239       if (pref_family_index > 0)
2240         {
2241           CFMutableArrayRef mutable_families =
2242             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2244           if (mutable_families)
2245             {
2246               CFArrayAppendValue (mutable_families,
2247                                   CFArrayGetValueAtIndex (families,
2248                                                           pref_family_index));
2249               CFArrayAppendArray (mutable_families, families,
2250                                   CFRangeMake (0, pref_family_index));
2251               if (pref_family_index + 1 < families_count)
2252                 CFArrayAppendArray (mutable_families, families,
2253                                     CFRangeMake (pref_family_index + 1,
2254                                                  families_count
2255                                                  - (pref_family_index + 1)));
2256               CFRelease (families);
2257               families = mutable_families;
2258             }
2259         }
2260     }
2262   charset = CFDictionaryGetValue (attributes,
2263                                   MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2264   if (charset)
2265     {
2266       CFRetain (charset);
2267       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2268     }
2269   else
2270     {
2271       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2272       if (! NILP (val))
2273         {
2274           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2275           if (CONSP (val) && VECTORP (XCDR (val)))
2276             chars = XCDR (val);
2277         }
2278       val = Qnil;
2279     }
2281   if (languages)
2282     {
2283       CFRetain (languages);
2284       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2285     }
2287   val = Qnil;
2288   extra = AREF (spec, FONT_EXTRA_INDEX);
2289   families_count = CFArrayGetCount (families);
2290   for (i = 0; i < families_count; i++)
2291     {
2292       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2293       FontDescriptorRef pat_desc;
2294       CFArrayRef descs;
2295       CFIndex descs_count;
2296       CFMutableArrayRef filtered_descs, traits_array;
2297       Lisp_Object entity;
2298       int j;
2300       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2301                             family_name);
2302       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2303       if (! pat_desc)
2304         goto err;
2306       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2307          10.7 returns NULL if pat_desc represents the LastResort font.
2308          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2309          trailing "s") for such a font.  */
2310       if (!CFEqual (family_name, CFSTR ("LastResort")))
2311         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2312                                                                       NULL);
2313       else
2314         {
2315           FontDescriptorRef lr_desc =
2316             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2317                                                                  NULL);
2318           if (lr_desc)
2319             {
2320               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2321                                      &kCFTypeArrayCallBacks);
2322               CFRelease (lr_desc);
2323             }
2324           else
2325             descs = NULL;
2326         }
2327       CFRelease (pat_desc);
2328       if (! descs)
2329         continue;
2331       descs_count = CFArrayGetCount (descs);
2332       if (descs_count == 0
2333           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2334                                                         charset, chars,
2335                                                         languages))
2336         {
2337           CFRelease (descs);
2338           continue;
2339         }
2341       filtered_descs =
2342         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2343       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2344       for (j = 0; j < descs_count; j++)
2345         {
2346           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2347           CFDictionaryRef dict;
2348           CFNumberRef num;
2349           FontSymbolicTraits sym_traits;
2351           dict = mac_font_descriptor_copy_attribute (desc,
2352                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2353           if (dict == NULL)
2354             continue;
2356           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2357           CFRelease (dict);
2358           if (num == NULL
2359               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2360             continue;
2362           if (spacing >= 0
2363               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2364               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2365                   != (spacing >= FONT_SPACING_MONO)))
2366             continue;
2368           /* Don't use a color bitmap font unless its family is
2369              explicitly specified.  */
2370           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2371             continue;
2373           if (j > 0
2374               && !macfont_supports_charset_and_languages_p (desc, charset,
2375                                                             chars, languages))
2376             continue;
2378           CFArrayAppendValue (filtered_descs, desc);
2379           CFArrayAppendValue (traits_array,
2380                               (const void *) (uintptr_t) sym_traits);
2381         }
2383       CFRelease (descs);
2384       descs = filtered_descs;
2385       descs_count = CFArrayGetCount (descs);
2387       for (j = 0; j < descs_count; j++)
2388         {
2389           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2390           FontSymbolicTraits sym_traits =
2391             ((FontSymbolicTraits) (uintptr_t)
2392              CFArrayGetValueAtIndex (traits_array, j));
2393           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2395           mask_min = ((synth_sym_traits ^ sym_traits)
2396                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2397           if (FONT_SLANT_NUMERIC (spec) < 0)
2398             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2399           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2400             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2402           mask_max = (synth_sym_traits & ~sym_traits);
2403           /* Synthetic bold does not work for bitmap-only fonts on Mac
2404              OS X 10.6.  */
2405           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2406             {
2407               CFNumberRef format =
2408                 mac_font_descriptor_copy_attribute (desc,
2409                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2411               if (format)
2412                 {
2413                   uint32_t format_val;
2415                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2416                                         &format_val)
2417                       && format_val == MAC_FONT_FORMAT_BITMAP)
2418                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2419                 }
2420             }
2421           if (spacing >= 0)
2422             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2424           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2425                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2426                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2427             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2428                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2429                  bmask += MAC_FONT_TRAIT_BOLD)
2430               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2431                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2432                    imask += MAC_FONT_TRAIT_ITALIC)
2433                 {
2434                   FontSymbolicTraits synth = (imask | bmask | mmask);
2436                   if (synth == 0
2437                       || macfont_closest_traits_index_p (traits_array,
2438                                                          (sym_traits | synth),
2439                                                          j))
2440                     {
2441                       entity = macfont_descriptor_entity (desc, extra, synth);
2442                       if (! NILP (entity))
2443                         val = Fcons (entity, val);
2444                     }
2445                 }
2446         }
2448       CFRelease (traits_array);
2449       CFRelease (descs);
2450     }
2452   CFRelease (families);
2453   val = Fnreverse (val);
2454   goto finish;
2455  err:
2456   val = Qnil;
2458  finish:
2459   FONT_ADD_LOG ("macfont-list", spec, val);
2460   if (charset) CFRelease (charset);
2461   if (languages) CFRelease (languages);
2462   if (attributes) CFRelease (attributes);
2463   if (family_name) CFRelease (family_name);
2465   unblock_input ();
2467   return val;
2470 static Lisp_Object
2471 macfont_match (struct frame * frame, Lisp_Object spec)
2473   Lisp_Object entity = Qnil;
2474   CFMutableDictionaryRef attributes;
2475   FontDescriptorRef pat_desc = NULL, desc = NULL;
2477   block_input ();
2479   attributes = macfont_create_attributes_with_spec (spec);
2480   if (attributes)
2481     {
2482       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2483       CFRelease (attributes);
2484     }
2485   if (pat_desc)
2486     {
2487       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2488                                                                   NULL);
2489       CFRelease (pat_desc);
2490     }
2491   if (desc)
2492     {
2493       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2494                                           0);
2495       CFRelease (desc);
2496     }
2497   unblock_input ();
2499   FONT_ADD_LOG ("macfont-match", spec, entity);
2500   return entity;
2503 static Lisp_Object
2504 macfont_list_family (struct frame *frame)
2506   Lisp_Object list = Qnil;
2507   CFArrayRef families;
2509   block_input ();
2511   families = macfont_copy_available_families_cache ();
2512   if (families)
2513     {
2514       CFIndex i, count = CFArrayGetCount (families);
2516       for (i = 0; i < count; i++)
2517         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2518       CFRelease (families);
2519     }
2521   unblock_input ();
2523   return list;
2526 static void
2527 macfont_free_entity (Lisp_Object entity)
2529   Lisp_Object val = assq_no_quit (QCfont_entity,
2530                                   AREF (entity, FONT_EXTRA_INDEX));
2531   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2533   block_input ();
2534   CFRelease (name);
2535   unblock_input ();
2538 static Lisp_Object
2539 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2541   Lisp_Object val, font_object;
2542   CFStringRef font_name;
2543   struct macfont_info *macfont_info = NULL;
2544   struct font *font;
2545   int size;
2546   FontRef macfont;
2547   FontSymbolicTraits sym_traits;
2548   char name[256];
2549   int len, i, total_width;
2550   CGGlyph glyph;
2551   CGFloat ascent, descent, leading;
2553   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2554   if (! CONSP (val)
2555       || XTYPE (XCDR (val)) != Lisp_Misc
2556       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2557     return Qnil;
2558   font_name = XSAVE_POINTER (XCDR (val), 0);
2559   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2561   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2562   if (size == 0)
2563     size = pixel_size;
2565   block_input ();
2566   macfont = mac_font_create_with_name (font_name, size);
2567   if (macfont)
2568     {
2569       int fontsize = (int) [((NSFont *) macfont) pointSize];
2570       if (fontsize != size) size = fontsize;
2571     }
2572   unblock_input ();
2573   if (! macfont)
2574     return Qnil;
2576   font_object = font_build_object (VECSIZE (struct macfont_info),
2577                                    Qmac_ct, entity, size);
2578   font = XFONT_OBJECT (font_object);
2579   font->pixel_size = size;
2580   font->driver = &macfont_driver;
2581   font->encoding_charset = font->repertory_charset = -1;
2583   block_input ();
2585   macfont_info = (struct macfont_info *) font;
2586   macfont_info->macfont = macfont;
2587   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2589   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2590   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2591     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2592                                                                   size);
2593   else
2594     macfont_info->screen_font = NULL;
2595   macfont_info->cache = macfont_lookup_cache (font_name);
2596   macfont_retain_cache (macfont_info->cache);
2597   macfont_info->metrics = NULL;
2598   macfont_info->metrics_nrows = 0;
2599   macfont_info->synthetic_italic_p = 0;
2600   macfont_info->synthetic_bold_p = 0;
2601   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2602   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2603   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2604       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2605     macfont_info->synthetic_italic_p = 1;
2606   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2607       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2608     macfont_info->synthetic_bold_p = 1;
2609   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2610     macfont_info->spacing = MACFONT_SPACING_MONO;
2611   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2612            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2613                == FONT_SPACING_SYNTHETIC_MONO))
2614     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2615   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2616     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2617   else
2618     {
2619       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2620       if (CONSP (val))
2621         macfont_info->antialias =
2622           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2623     }
2624   macfont_info->color_bitmap_p = 0;
2625   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2626     macfont_info->color_bitmap_p = 1;
2628   glyph = macfont_get_glyph_for_character (font, ' ');
2629   if (glyph != kCGFontIndexInvalid)
2630     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2631   else
2632     /* dirty workaround */
2633     font->space_width = pixel_size;
2635   total_width = font->space_width;
2636   for (i = 1; i < 95; i++)
2637     {
2638       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2639       if (glyph == kCGFontIndexInvalid)
2640         break;
2641       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2642     }
2643   if (i == 95)
2644     font->average_width = total_width / 95;
2645   else
2646     font->average_width = font->space_width; /* XXX */
2648   if (!(macfont_info->screen_font
2649         && mac_screen_font_get_metrics (macfont_info->screen_font,
2650                                         &ascent, &descent, &leading)))
2651     {
2652       CFStringRef family_name;
2654       ascent = mac_font_get_ascent (macfont);
2655       descent = mac_font_get_descent (macfont);
2656       leading = mac_font_get_leading (macfont);
2657       /* AppKit and WebKit do some adjustment to the heights of
2658          Courier, Helvetica, and Times.  */
2659       family_name = mac_font_copy_family_name (macfont);
2660       if (family_name)
2661         {
2662           if (CFEqual (family_name, CFSTR ("Courier"))
2663               || CFEqual (family_name, CFSTR ("Helvetica"))
2664               || CFEqual (family_name, CFSTR ("Times")))
2665             ascent += (ascent + descent) * .15f;
2666           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2667             {
2668               leading *= .25f;
2669               ascent += leading;
2670             }
2671           CFRelease (family_name);
2672         }
2673     }
2674   font->ascent = ascent + 0.5f;
2675   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2676   if (CONSP (val) && !NILP (XCDR (val)))
2677     font->descent = descent + 0.5f;
2678   else
2679     font->descent = descent + leading + 0.5f;
2680   font->height = font->ascent + font->descent;
2682   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2683   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2685   unblock_input ();
2687   /* Unfortunately Xft doesn't provide a way to get minimum char
2688      width.  So, we use space_width instead.  */
2689   font->min_width = font->max_width = font->space_width; /* XXX */
2691   font->baseline_offset = 0;
2692   font->relative_compose = 0;
2693   font->default_ascent = 0;
2694   font->vertical_centering = 0;
2696   return font_object;
2699 static void
2700 macfont_close (struct font *font)
2702   struct macfont_info *macfont_info = (struct macfont_info *) font;
2704   if (macfont_info->cache)
2705     {
2706       int i;
2708       block_input ();
2709       CFRelease (macfont_info->macfont);
2710       CGFontRelease (macfont_info->cgfont);
2711       if (macfont_info->screen_font)
2712         CFRelease (macfont_info->screen_font);
2713       macfont_release_cache (macfont_info->cache);
2714       for (i = 0; i < macfont_info->metrics_nrows; i++)
2715         if (macfont_info->metrics[i])
2716           xfree (macfont_info->metrics[i]);
2717       if (macfont_info->metrics)
2718         xfree (macfont_info->metrics);
2719       macfont_info->cache = NULL;
2720       unblock_input ();
2721     }
2724 static int
2725 macfont_has_char (Lisp_Object font, int c)
2727   int result;
2728   CFCharacterSetRef charset;
2730   block_input ();
2731   if (FONT_ENTITY_P (font))
2732     {
2733       Lisp_Object val;
2734       CFStringRef name;
2736       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2737       val = XCDR (val);
2738       name = XSAVE_POINTER (val, 0);
2739       charset = macfont_get_cf_charset_for_name (name);
2740     }
2741   else
2742     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2744   result = CFCharacterSetIsLongCharacterMember (charset, c);
2745   unblock_input ();
2747   return result;
2750 static unsigned
2751 macfont_encode_char (struct font *font, int c)
2753   struct macfont_info *macfont_info = (struct macfont_info *) font;
2754   CGGlyph glyph;
2756   block_input ();
2757   glyph = macfont_get_glyph_for_character (font, c);
2758   unblock_input ();
2760   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2763 static void
2764 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2765                       struct font_metrics *metrics)
2767   int width, i;
2769   block_input ();
2770   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2771   for (i = 1; i < nglyphs; i++)
2772     {
2773       struct font_metrics m;
2774       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2775                                      NULL, 0);
2777       if (metrics)
2778         {
2779           if (width + m.lbearing < metrics->lbearing)
2780             metrics->lbearing = width + m.lbearing;
2781           if (width + m.rbearing > metrics->rbearing)
2782             metrics->rbearing = width + m.rbearing;
2783           if (m.ascent > metrics->ascent)
2784             metrics->ascent = m.ascent;
2785           if (m.descent > metrics->descent)
2786             metrics->descent = m.descent;
2787         }
2788       width += w;
2789     }
2790   unblock_input ();
2792   if (metrics)
2793     metrics->width = width;
2796 static int
2797 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2798               bool with_background)
2800   struct frame * f = s->f;
2801   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2802   CGRect background_rect;
2803   CGPoint text_position;
2804   CGGlyph *glyphs;
2805   CGPoint *positions;
2806   CGFloat font_size = mac_font_get_size (macfont_info->macfont);
2807   bool no_antialias_p =
2808     (NILP (ns_antialias_text)
2809      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2810      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2811          && font_size <= macfont_antialias_threshold));
2812   int len = to - from;
2813   struct face *face = s->face;
2814   CGContextRef context;
2816   block_input ();
2818   if (with_background)
2819     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2820                                   s->width, FONT_HEIGHT (s->font));
2821   else
2822     background_rect = CGRectNull;
2824   text_position = CGPointMake (x, -y);
2825   glyphs = xmalloc (sizeof (CGGlyph) * len);
2826   {
2827     CGFloat advance_delta = 0;
2828     int i;
2829     CGFloat total_width = 0;
2831     positions = xmalloc (sizeof (CGPoint) * len);
2832     for (i = 0; i < len; i++)
2833       {
2834         int width;
2836         glyphs[i] = s->char2b[from + i];
2837         width = (s->padding_p ? 1
2838                  : macfont_glyph_extents (s->font, glyphs[i],
2839                                           NULL, &advance_delta,
2840                                           no_antialias_p));
2841         positions[i].x = total_width + advance_delta;
2842         positions[i].y = 0;
2843         total_width += width;
2844       }
2845   }
2847   context = [[NSGraphicsContext currentContext] graphicsPort];
2848   CGContextSaveGState (context);
2850   if (!CGRectIsNull (background_rect))
2851     {
2852       if (s->hl == DRAW_MOUSE_FACE)
2853         {
2854           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2855           if (!face)
2856             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2857         }
2858       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2859       CGContextFillRects (context, &background_rect, 1);
2860     }
2862   if (macfont_info->cgfont)
2863     {
2864       CGAffineTransform atfm;
2866       CGContextScaleCTM (context, 1, -1);
2867       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2868       if (macfont_info->synthetic_italic_p)
2869         atfm = synthetic_italic_atfm;
2870       else
2871         atfm = CGAffineTransformIdentity;
2872       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2873         {
2874           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2875           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2876           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2877         }
2878       if (no_antialias_p)
2879         CGContextSetShouldAntialias (context, false);
2881       CGContextSetTextMatrix (context, atfm);
2882       CGContextSetTextPosition (context, text_position.x, text_position.y);
2884 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2885       if (macfont_info->color_bitmap_p
2886 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2887           && CTFontDrawGlyphs != NULL
2888 #endif
2889           )
2890         {
2891           if (len > 0)
2892             {
2893               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2894                                 context);
2895             }
2896         }
2897       else
2898 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2899         {
2900           CGContextSetFont (context, macfont_info->cgfont);
2901           CGContextSetFontSize (context, font_size);
2902           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2903         }
2904     }
2907   xfree (glyphs);
2908   xfree (positions);
2909   CGContextRestoreGState (context);
2911   unblock_input ();
2913   return len;
2916 static Lisp_Object
2917 macfont_shape (Lisp_Object lgstring)
2919   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2920   struct macfont_info *macfont_info = (struct macfont_info *) font;
2921   FontRef macfont = macfont_info->macfont;
2922   ptrdiff_t glyph_len, len, i, j;
2923   CFIndex nonbmp_len;
2924   UniChar *unichars;
2925   CFIndex *nonbmp_indices;
2926   CFStringRef string;
2927   CFIndex used = 0;
2928   struct mac_glyph_layout *glyph_layouts;
2930   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2931   nonbmp_len = 0;
2932   for (i = 0; i < glyph_len; i++)
2933     {
2934       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2936       if (NILP (lglyph))
2937         break;
2938       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2939         nonbmp_len++;
2940     }
2942   len = i;
2944   if (INT_MAX / 2 < len)
2945     memory_full (SIZE_MAX);
2947   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2948   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2949   for (i = j = 0; i < len; i++)
2950     {
2951       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2953       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2954         {
2955           nonbmp_indices[j] = i + j;
2956           j++;
2957         }
2958     }
2959   nonbmp_indices[j] = len + j;  /* sentinel */
2961   block_input ();
2963   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2964                                                kCFAllocatorNull);
2965   if (string)
2966     {
2967       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2968       if (macfont_info->screen_font)
2969         used = mac_screen_font_shape (macfont_info->screen_font, string,
2970                                       glyph_layouts, glyph_len);
2971       else
2972         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2973       CFRelease (string);
2974     }
2976   unblock_input ();
2978   if (used == 0)
2979     return Qnil;
2981   block_input ();
2983   for (i = 0; i < used; i++)
2984     {
2985       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2986       struct mac_glyph_layout *gl = glyph_layouts + i;
2987       EMACS_INT from, to;
2988       struct font_metrics metrics;
2989       int xoff, yoff, wadjust;
2991       if (NILP (lglyph))
2992         {
2993           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2994           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2995         }
2997       from = gl->comp_range.location;
2998       /* Convert UTF-16 index to UTF-32.  */
2999       j = 0;
3000       while (nonbmp_indices[j] < from)
3001         j++;
3002       from -= j;
3003       LGLYPH_SET_FROM (lglyph, from);
3005       to = gl->comp_range.location + gl->comp_range.length;
3006       /* Convert UTF-16 index to UTF-32.  */
3007       while (nonbmp_indices[j] < to)
3008         j++;
3009       to -= j;
3010       LGLYPH_SET_TO (lglyph, to - 1);
3012       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3013          the composition is trivial.  */
3014       {
3015         UTF32Char c;
3017         if (unichars[gl->string_index] >= 0xD800
3018             && unichars[gl->string_index] < 0xDC00)
3019           c = (((unichars[gl->string_index] - 0xD800) << 10)
3020                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3021         else
3022           c = unichars[gl->string_index];
3023         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3024           c = 0;
3025         LGLYPH_SET_CHAR (lglyph, c);
3026       }
3028       {
3029         unsigned long cc = gl->glyph_id;
3030         LGLYPH_SET_CODE (lglyph, cc);
3031       }
3033       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3034       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3035       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3036       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3037       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3038       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3040       xoff = lround (gl->advance_delta);
3041       yoff = lround (- gl->baseline_delta);
3042       wadjust = lround (gl->advance);
3043       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3044         {
3045           Lisp_Object vec;
3047           vec = Fmake_vector (make_number (3), Qnil);
3048           ASET (vec, 0, make_number (xoff));
3049           ASET (vec, 1, make_number (yoff));
3050           ASET (vec, 2, make_number (wadjust));
3051           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3052         }
3053     }
3055   unblock_input ();
3057   return make_number (used);
3060 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3061 typedef UInt8 UINT24[3];
3063 #pragma pack(push, 1)
3064 struct variation_selector_record
3066   UINT24 var_selector;
3067   UInt32 default_uvs_offset, non_default_uvs_offset;
3069 struct uvs_table
3071   UInt16 format;
3072   UInt32 length, num_var_selector_records;
3073   struct variation_selector_record variation_selector_records[1];
3075 #define SIZEOF_UVS_TABLE_HEADER                                         \
3076   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3078 struct unicode_value_range
3080   UINT24 start_unicode_value;
3081   UInt8 additional_count;
3083 struct default_uvs_table {
3084   UInt32 num_unicode_value_ranges;
3085   struct unicode_value_range unicode_value_ranges[1];
3087 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3088   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3090 struct uvs_mapping
3092   UINT24 unicode_value;
3093   UInt16 glyph_id;
3095 struct non_default_uvs_table
3097   UInt32 num_uvs_mappings;
3098   struct uvs_mapping uvs_mappings[1];
3100 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3101   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3102 #pragma pack(pop)
3104 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3105 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3106    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3107    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3108 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3109 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3110 /* Succeeding one byte should also be accessible.  */
3111 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3112 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3114 /* Return UVS subtable for the specified FONT.  If the subtable is not
3115    found or ill-formatted, then return NULL.  */
3117 static CFDataRef
3118 mac_font_copy_uvs_table (FontRef font)
3120   CFDataRef cmap_table, uvs_table = NULL;
3122   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3123   if (cmap_table)
3124     {
3125       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3126       struct uvs_table *uvs;
3127       struct variation_selector_record *records;
3128       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3130 #if __LP64__
3131       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3132         goto finish;
3133 #endif
3135       cmap_len = CFDataGetLength (cmap_table);
3136       if (sizeof_sfntCMapHeader > cmap_len)
3137         goto finish;
3139       ntables = BUINT16_VALUE (cmap->numTables);
3140       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3141                      / sizeof_sfntCMapEncoding))
3142         goto finish;
3144       for (i = 0; i < ntables; i++)
3145         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3146              == kFontUnicodePlatform)
3147             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3148                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3149           {
3150             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3151             break;
3152           }
3153       if (i == ntables
3154           || uvs_offset > cmap_len
3155           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3156         goto finish;
3158       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3159       uvs_len = BUINT32_VALUE (uvs->length);
3160       if (uvs_len > cmap_len - uvs_offset
3161           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3162         goto finish;
3164       if (BUINT16_VALUE (uvs->format) != 14)
3165         goto finish;
3167       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3168       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3169                       / sizeof (struct variation_selector_record)))
3170         goto finish;
3172       records = uvs->variation_selector_records;
3173       for (i = 0; i < nrecords; i++)
3174         {
3175           UInt32 default_uvs_offset, non_default_uvs_offset;
3177           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3178           if (default_uvs_offset)
3179             {
3180               struct default_uvs_table *default_uvs;
3181               UInt32 nranges;
3183               if (default_uvs_offset > uvs_len
3184                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3185                       > uvs_len - default_uvs_offset))
3186                 goto finish;
3188               default_uvs = ((struct default_uvs_table *)
3189                              ((UInt8 *) uvs + default_uvs_offset));
3190               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3191               if (nranges > ((uvs_len - default_uvs_offset
3192                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3193                              / sizeof (struct unicode_value_range)))
3194                 goto finish;
3195               /* Now 2 * nranges can't overflow, so we can safely use
3196                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3197                  mac_font_get_glyphs_for_variants.  */
3198             }
3200           non_default_uvs_offset =
3201             BUINT32_VALUE (records[i].non_default_uvs_offset);
3202           if (non_default_uvs_offset)
3203             {
3204               struct non_default_uvs_table *non_default_uvs;
3205               UInt32 nmappings;
3207               if (non_default_uvs_offset > uvs_len
3208                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3209                       > uvs_len - non_default_uvs_offset))
3210                 goto finish;
3212               non_default_uvs = ((struct non_default_uvs_table *)
3213                                  ((UInt8 *) uvs + non_default_uvs_offset));
3214               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3215               if (nmappings > ((uvs_len - non_default_uvs_offset
3216                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3217                                / sizeof (struct uvs_mapping)))
3218                 goto finish;
3219               /* Now 2 * nmappings can't overflow, so we can safely
3220                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3221                  in mac_font_get_glyphs_for_variants.  */
3222             }
3223         }
3225       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3227     finish:
3228       CFRelease (cmap_table);
3229     }
3231   return uvs_table;
3234 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3235    sequence consisting of the given base character C and each
3236    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3237    result (explained below) into the corresponding GLYPHS[i].  If the
3238    entry is found in the Default UVS Table, then the result is 0.  If
3239    the entry is found in the Non-Default UVS Table, then the result is
3240    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3241    elements in SELECTORS must be sorted in strictly increasing
3242    order.  */
3244 static void
3245 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3246                                   const UTF32Char selectors[], CGGlyph glyphs[],
3247                                   CFIndex count)
3249   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3250   struct variation_selector_record *records = uvs->variation_selector_records;
3251   CFIndex i;
3252   UInt32 ir, nrecords;
3253   dispatch_queue_t queue =
3254     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3255   dispatch_group_t group = dispatch_group_create ();
3257   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3258   i = 0;
3259   ir = 0;
3260   while (i < count && ir < nrecords)
3261     {
3262       UInt32 default_uvs_offset, non_default_uvs_offset;
3264       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3265         {
3266           glyphs[i++] = kCGFontIndexInvalid;
3267           continue;
3268         }
3269       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3270         {
3271           ir++;
3272           continue;
3273         }
3275       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3276       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3277       non_default_uvs_offset =
3278         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3279       dispatch_group_async (group, queue, ^{
3280           glyphs[i] = kCGFontIndexInvalid;
3282           if (default_uvs_offset)
3283             {
3284               struct default_uvs_table *default_uvs =
3285                 (struct default_uvs_table *) ((UInt8 *) uvs
3286                                               + default_uvs_offset);
3287               struct unicode_value_range *ranges =
3288                 default_uvs->unicode_value_ranges;
3289               UInt32 lo, hi;
3291               lo = 0;
3292               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3293               while (lo < hi)
3294                 {
3295                   UInt32 mid = (lo + hi) / 2;
3297                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3298                     hi = mid;
3299                   else
3300                     lo = mid + 1;
3301                 }
3302               if (hi > 0
3303                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3304                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3305                 glyphs[i] = 0;
3306             }
3308           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3309             {
3310               struct non_default_uvs_table *non_default_uvs =
3311                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3312                                                   + non_default_uvs_offset);
3313               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3314               UInt32 lo, hi;
3316               lo = 0;
3317               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3318               while (lo < hi)
3319                 {
3320                   UInt32 mid = (lo + hi) / 2;
3322                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3323                     hi = mid;
3324                   else
3325                     lo = mid + 1;
3326                 }
3327               if (hi > 0 &&
3328                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3329                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3330             }
3331         });
3332       i++;
3333       ir++;
3334     }
3335   while (i < count)
3336     glyphs[i++] = kCGFontIndexInvalid;
3337   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3338   dispatch_release (group);
3341 static int
3342 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3344   CFDataRef uvs_table;
3345   CharacterCollection uvs_collection;
3346   int i, n = 0;
3348   block_input ();
3349   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3351   if (uvs_table)
3352     {
3353       UTF32Char selectors[256];
3354       CGGlyph glyphs[256];
3356       for (i = 0; i < 16; i++)
3357         selectors[i] = 0xFE00 + i;
3358       for (; i < 256; i++)
3359         selectors[i] = 0xE0100 + (i - 16);
3360       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3361       for (i = 0; i < 256; i++)
3362         {
3363           CGGlyph glyph = glyphs[i];
3365           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3366               && glyph != kCGFontIndexInvalid)
3367             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3368           if (glyph == kCGFontIndexInvalid)
3369             variations[i] = 0;
3370           else
3371             {
3372               variations[i] = (glyph ? glyph
3373                                : macfont_get_glyph_for_character (font, c));
3374               n++;
3375             }
3376         }
3377     }
3378   unblock_input ();
3380   return n;
3383 static const char *const macfont_booleans[] = {
3384   ":antialias",
3385   ":minspace",
3386   NULL,
3389 static const char *const macfont_non_booleans[] = {
3390   ":lang",
3391   ":script",
3392   ":destination",
3393   NULL,
3396 static void
3397 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3399   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3402 static Boolean
3403 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3404                                           CFArrayRef languages)
3406   Boolean result = true;
3407   CFArrayRef desc_languages =
3408     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3410   if (desc_languages == NULL)
3411     result = false;
3412   else
3413     {
3414       CFIndex desc_languages_count, i, languages_count;
3416       desc_languages_count = CFArrayGetCount (desc_languages);
3417       languages_count = CFArrayGetCount (languages);
3418       for (i = 0; i < languages_count; i++)
3419         if (!CFArrayContainsValue (desc_languages,
3420                                    CFRangeMake (0, desc_languages_count),
3421                                    CFArrayGetValueAtIndex (languages, i)))
3422           {
3423             result = false;
3424             break;
3425           }
3426       CFRelease (desc_languages);
3427     }
3429   return result;
3432 static CFStringRef
3433 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3435   CFStringRef result = NULL;
3436   CFStringRef charset_string =
3437     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3439   if (charset_string && CFStringGetLength (charset_string) > 0)
3440     {
3441       CFStringRef keys[] = {
3442 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3443         kCTLanguageAttributeName
3444 #else
3445         CFSTR ("NSLanguage")
3446 #endif
3447       };
3448       CFTypeRef values[] = {NULL};
3449       CFIndex num_values = 0;
3450       CFArrayRef languages
3451         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3453       if (languages && CFArrayGetCount (languages) > 0)
3454         {
3455           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3456             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3457           else
3458             {
3459               CFCharacterSetRef charset =
3460                 CFDictionaryGetValue (attributes,
3461                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3463               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3464             }
3465         }
3466       if (result == NULL)
3467         {
3468           CFAttributedStringRef attr_string = NULL;
3469           CTLineRef ctline = NULL;
3470           CFDictionaryRef attrs
3471             = CFDictionaryCreate (NULL, (const void **) keys,
3472                                   (const void **) values, num_values,
3473                                   &kCFTypeDictionaryKeyCallBacks,
3474                                   &kCFTypeDictionaryValueCallBacks);
3476           if (attrs)
3477             {
3478               attr_string = CFAttributedStringCreate (NULL, charset_string,
3479                                                       attrs);
3480               CFRelease (attrs);
3481             }
3482           if (attr_string)
3483             {
3484               ctline = CTLineCreateWithAttributedString (attr_string);
3485               CFRelease (attr_string);
3486             }
3487           if (ctline)
3488             {
3489               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3490               CFIndex i, nruns = CFArrayGetCount (runs);
3491               CTFontRef font;
3493               for (i = 0; i < nruns; i++)
3494                 {
3495                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3496                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3497                   CTFontRef font_in_run;
3499                   if (attributes == NULL)
3500                     break;
3501                   font_in_run =
3502                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3503                   if (font_in_run == NULL)
3504                     break;
3505                   if (i == 0)
3506                     font = font_in_run;
3507                   else if (!mac_ctfont_equal_in_postscript_name (font,
3508                                                                  font_in_run))
3509                     break;
3510                 }
3511               if (nruns > 0 && i == nruns)
3512                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3513               CFRelease (ctline);
3514             }
3515         }
3516     }
3518   return result;
3521 static inline double
3522 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3524   return CTFontGetAdvancesForGlyphs (font,
3525 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3526                                      kCTFontOrientationDefault,
3527 #else
3528                                      kCTFontDefaultOrientation,
3529 #endif
3530                                      &glyph, NULL, 1);
3533 static inline CGRect
3534 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3536   return CTFontGetBoundingRectsForGlyphs (font,
3537 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3538                                           kCTFontOrientationDefault,
3539 #else
3540                                           kCTFontDefaultOrientation,
3541 #endif
3542                                           &glyph, NULL, 1);
3545 static CFArrayRef
3546 mac_ctfont_create_available_families (void)
3548   CFMutableArrayRef families = NULL;
3550     {
3551       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3553       if (orig_families)
3554         {
3555           CFIndex i, count = CFArrayGetCount (orig_families);
3557           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3558           if (families)
3559             for (i = 0; i < count; i++)
3560               {
3561                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3563                 if (!CFStringHasPrefix (family, CFSTR ("."))
3564                     && (CTFontManagerCompareFontFamilyNames (family,
3565                                                              CFSTR ("LastResort"),
3566                                                              NULL)
3567                         != kCFCompareEqualTo))
3568                   CFArrayAppendValue (families, family);
3569               }
3570           CFRelease (orig_families);
3571         }
3572     }
3574     return families;
3577 static Boolean
3578 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3580   Boolean result;
3581   CFStringRef name1, name2;
3583   if (font1 == font2)
3584     return true;
3586   result = false;
3587   name1 = CTFontCopyPostScriptName (font1);
3588   if (name1)
3589     {
3590       name2 = CTFontCopyPostScriptName (font2);
3591       if (name2)
3592         {
3593           result = CFEqual (name1, name2);
3594           CFRelease (name2);
3595         }
3596       CFRelease (name1);
3597     }
3599   return result;
3602 static CTLineRef
3603 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3604                                              CTFontRef macfont)
3606   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3607   CFTypeRef values[] = {NULL, NULL};
3608   CFDictionaryRef attributes = NULL;
3609   CFAttributedStringRef attr_string = NULL;
3610   CTLineRef ctline = NULL;
3611   float float_zero = 0.0f;
3613   values[0] = macfont;
3614   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3615   if (values[1])
3616     {
3617       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3618                                        (const void **) values,
3619                                        ARRAYELTS (keys),
3620                                        &kCFTypeDictionaryKeyCallBacks,
3621                                        &kCFTypeDictionaryValueCallBacks);
3622       CFRelease (values[1]);
3623     }
3624   if (attributes)
3625     {
3626       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3627       CFRelease (attributes);
3628     }
3629   if (attr_string)
3630     {
3631       ctline = CTLineCreateWithAttributedString (attr_string);
3632       CFRelease (attr_string);
3633     }
3634   if (ctline)
3635     {
3636       /* Abandon if ctline contains some fonts other than the
3637          specified one.  */
3638       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3639       CFIndex i, nruns = CFArrayGetCount (runs);
3641       for (i = 0; i < nruns; i++)
3642         {
3643           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3644           CFDictionaryRef attributes = CTRunGetAttributes (run);
3645           CTFontRef font_in_run;
3647           if (attributes == NULL)
3648             break;
3649           font_in_run =
3650             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3651           if (font_in_run == NULL)
3652             break;
3653           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3654             break;
3655         }
3656       if (i < nruns)
3657         {
3658           CFRelease (ctline);
3659           ctline = NULL;
3660         }
3661     }
3663   return ctline;
3666 static CFIndex
3667 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3668                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3670   CFIndex used, result = 0;
3671   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3673   if (ctline == NULL)
3674     return 0;
3676   used = CTLineGetGlyphCount (ctline);
3677   if (used <= glyph_len)
3678     {
3679       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3680       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3681       CGFloat total_advance = 0;
3682       CFIndex total_glyph_count = 0;
3684       for (k = 0; k < ctrun_count; k++)
3685         {
3686           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3687           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3688           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3689           CFRange string_range, comp_range, range;
3690           CFIndex *permutation;
3692           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3693             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3694           else
3695             permutation = NULL;
3697 #define RIGHT_TO_LEFT_P permutation
3699           /* Now the `comp_range' member of struct mac_glyph_layout is
3700              temporarily used as a work area such that:
3701              glbuf[i].comp_range.location =
3702              min {compRange[i + 1].location, ...,
3703                      compRange[glyph_count - 1].location,
3704                      maxRange (stringRangeForCTRun)}
3705              glbuf[i].comp_range.length = maxRange (compRange[i])
3706              where compRange[i] is the range of composed characters
3707              containing i-th glyph.  */
3708           string_range = CTRunGetStringRange (ctrun);
3709           min_location = string_range.location + string_range.length;
3710           for (i = 0; i < glyph_count; i++)
3711             {
3712               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3713               CFIndex glyph_index;
3714               CFRange rng;
3716               if (!RIGHT_TO_LEFT_P)
3717                 glyph_index = glyph_count - i - 1;
3718               else
3719                 glyph_index = i;
3720               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3721                                      &gl->string_index);
3722               rng =
3723                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3724                                                              gl->string_index);
3725               gl->comp_range.location = min_location;
3726               gl->comp_range.length = rng.location + rng.length;
3727               if (rng.location < min_location)
3728                 min_location = rng.location;
3729             }
3731           /* Fill the `comp_range' member of struct mac_glyph_layout,
3732              and setup a permutation for right-to-left text.  */
3733           comp_range = CFRangeMake (string_range.location, 0);
3734           range = CFRangeMake (0, 0);
3735           while (1)
3736             {
3737               struct mac_glyph_layout *gl =
3738                 glbuf + range.location + range.length;
3740               if (gl->comp_range.length
3741                   > comp_range.location + comp_range.length)
3742                 comp_range.length = gl->comp_range.length - comp_range.location;
3743               min_location = gl->comp_range.location;
3744               range.length++;
3746               if (min_location >= comp_range.location + comp_range.length)
3747                 {
3748                   comp_range.length = min_location - comp_range.location;
3749                   for (i = 0; i < range.length; i++)
3750                     {
3751                       glbuf[range.location + i].comp_range = comp_range;
3752                       if (RIGHT_TO_LEFT_P)
3753                         permutation[range.location + i] =
3754                           range.location + range.length - i - 1;
3755                     }
3757                   comp_range = CFRangeMake (min_location, 0);
3758                   range.location += range.length;
3759                   range.length = 0;
3760                   if (range.location == glyph_count)
3761                     break;
3762                 }
3763             }
3765           /* Then fill the remaining members.  */
3766           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3767                range.location++)
3768             {
3769               struct mac_glyph_layout *gl;
3770               CGPoint position;
3772               if (!RIGHT_TO_LEFT_P)
3773                 gl = glbuf + range.location;
3774               else
3775                 {
3776                   CFIndex src, dest;
3778                   src = glyph_count - 1 - range.location;
3779                   dest = permutation[src];
3780                   gl = glbuf + dest;
3781                   if (src < dest)
3782                     {
3783                       CFIndex tmp = gl->string_index;
3785                       gl->string_index = glbuf[src].string_index;
3786                       glbuf[src].string_index = tmp;
3787                     }
3788                 }
3789               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3791               CTRunGetPositions (ctrun, range, &position);
3792               gl->advance_delta = position.x - total_advance;
3793               gl->baseline_delta = position.y;
3794               gl->advance = (gl->advance_delta
3795                              + CTRunGetTypographicBounds (ctrun, range,
3796                                                           NULL, NULL, NULL));
3797               total_advance += gl->advance;
3798             }
3800           if (RIGHT_TO_LEFT_P)
3801             xfree (permutation);
3803 #undef RIGHT_TO_LEFT_P
3805           total_glyph_count += glyph_count;
3806         }
3808       result = used;
3809     }
3810   CFRelease (ctline);
3812   return result;
3815 /* The function below seems to cause a memory leak for the CFString
3816    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3817    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3818 #if USE_CT_GLYPH_INFO
3819 static CGGlyph
3820 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3821                               CGFontIndex cid)
3823   CGGlyph result = kCGFontIndexInvalid;
3824   UniChar characters[] = {0xfffd};
3825   CFStringRef string;
3826   CFAttributedStringRef attr_string = NULL;
3827   CTLineRef ctline = NULL;
3829   string = CFStringCreateWithCharacters (NULL, characters,
3830                                          ARRAYELTS (characters));
3832   if (string)
3833     {
3834       CTGlyphInfoRef glyph_info =
3835         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3836       CFDictionaryRef attributes = NULL;
3838       if (glyph_info)
3839         {
3840           CFStringRef keys[] = {kCTFontAttributeName,
3841                                 kCTGlyphInfoAttributeName};
3842           CFTypeRef values[] = {font, glyph_info};
3844           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3845                                            (const void **) values,
3846                                            ARRAYELTS (keys),
3847                                            &kCFTypeDictionaryKeyCallBacks,
3848                                            &kCFTypeDictionaryValueCallBacks);
3849           CFRelease (glyph_info);
3850         }
3851       if (attributes)
3852         {
3853           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3854           CFRelease (attributes);
3855         }
3856       CFRelease (string);
3857     }
3858   if (attr_string)
3859     {
3860       ctline = CTLineCreateWithAttributedString (attr_string);
3861       CFRelease (attr_string);
3862     }
3863   if (ctline)
3864     {
3865       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3867       if (CFArrayGetCount (runs) > 0)
3868         {
3869           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3870           CFDictionaryRef attributes = CTRunGetAttributes (run);
3872           if (attributes)
3873             {
3874               CTFontRef font_in_run =
3875                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3877               if (font_in_run
3878                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3879                 {
3880                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3881                   if (result >= CTFontGetGlyphCount (font))
3882                     result = kCGFontIndexInvalid;
3883                 }
3884             }
3885         }
3886       CFRelease (ctline);
3887     }
3889   return result;
3891 #endif
3893 static CFArrayRef
3894 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3896   CFArrayRef result = NULL;
3898 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3899 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3900   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3901 #endif
3902     {
3903       CTFontRef user_font =
3904         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3906       if (user_font)
3907         {
3908           CFArrayRef languages =
3909             CFArrayCreate (NULL, (const void **) &language, 1,
3910                            &kCFTypeArrayCallBacks);
3912           if (languages)
3913             {
3914               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3915                                                                  languages);
3916               CFRelease (languages);
3917             }
3918           CFRelease (user_font);
3919         }
3920     }
3921 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3922   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3923 #endif
3924 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3925 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3926     {
3927       CFIndex i;
3929       for (i = 0; macfont_language_default_font_names[i].language; i++)
3930         {
3931           if (CFEqual (macfont_language_default_font_names[i].language,
3932                        language))
3933             {
3934               CFMutableArrayRef descriptors =
3935                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3937               if (descriptors)
3938                 {
3939                   CFIndex j;
3941                   for (j = 0;
3942                        macfont_language_default_font_names[i].font_names[j];
3943                        j++)
3944                     {
3945                       CFDictionaryRef attributes =
3946                         CFDictionaryCreate (NULL,
3947                                             ((const void **)
3948                                              &MAC_FONT_NAME_ATTRIBUTE),
3949                                             ((const void **)
3950                                              &macfont_language_default_font_names[i].font_names[j]),
3951                                             1, &kCFTypeDictionaryKeyCallBacks,
3952                                             &kCFTypeDictionaryValueCallBacks);
3954                       if (attributes)
3955                         {
3956                           FontDescriptorRef pat_desc =
3957                             mac_font_descriptor_create_with_attributes (attributes);
3959                           if (pat_desc)
3960                             {
3961                               FontDescriptorRef descriptor =
3962                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3964                               if (descriptor)
3965                                 {
3966                                   CFArrayAppendValue (descriptors, descriptor);
3967                                   CFRelease (descriptor);
3968                                 }
3969                               CFRelease (pat_desc);
3970                             }
3971                           CFRelease (attributes);
3972                         }
3973                     }
3974                   result = descriptors;
3975                 }
3976               break;
3977             }
3978         }
3979     }
3980 #endif
3982   return result;
3985 static CFStringRef
3986 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3987                                                       CFArrayRef languages)
3989   CFStringRef result = NULL;
3990   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3991   CFArrayRef descriptors =
3992     mac_font_copy_default_descriptors_for_language (language);
3994   if (descriptors)
3995     {
3996       CFIndex i, count = CFArrayGetCount (descriptors);
3998       for (i = 0; i < count; i++)
3999         {
4000           FontDescriptorRef descriptor =
4001             CFArrayGetValueAtIndex (descriptors, i);
4003           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4004                                                         Qnil, languages))
4005             {
4006               CFStringRef family =
4007                 mac_font_descriptor_copy_attribute (descriptor,
4008                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4009               if (family)
4010                 {
4011                   if (!CFStringHasPrefix (family, CFSTR ("."))
4012                       && !CFEqual (family, CFSTR ("LastResort")))
4013                     {
4014                       result = family;
4015                       break;
4016                     }
4017                   else
4018                     CFRelease (family);
4019                 }
4020             }
4021         }
4022       CFRelease (descriptors);
4023     }
4025   return result;
4028 void *
4029 macfont_get_nsctfont (struct font *font)
4031   struct macfont_info *macfont_info = (struct macfont_info *) font;
4032   FontRef macfont = macfont_info->macfont;
4034   return (void *) macfont;
4037 void
4038 mac_register_font_driver (struct frame *f)
4040   register_font_driver (&macfont_driver, f);
4044 void
4045 syms_of_macfont (void)
4047   static struct font_driver mac_font_driver;
4049   /* Core Text, for Mac OS X.  */
4050   DEFSYM (Qmac_ct, "mac-ct");
4051   macfont_driver.type = Qmac_ct;
4052   register_font_driver (&macfont_driver, NULL);
4054   /* The font property key specifying the font design destination.  The
4055      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4056      text.  (See the documentation of X Logical Font Description
4057      Conventions.)  In the Mac font driver, 1 means the screen font is
4058      used for calculating some glyph metrics.  You can see the
4059      difference with Monaco 8pt or 9pt, for example.  */
4060   DEFSYM (QCdestination, ":destination");
4062   /* The boolean-valued font property key specifying the use of leading.  */
4063   DEFSYM (QCminspace, ":minspace");
4065   macfont_family_cache = Qnil;
4066   staticpro (&macfont_family_cache);