Fix (mapcar F S) crash when F alters S’s length
[emacs.git] / src / macfont.m
blobc799100c8550823ac84311d5eae0f2f0c9474bec
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2016 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 (at
9 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_font_get_advance_width_for_glyph (CTFontRef, CGGlyph);
44 static CGRect mac_font_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
45 static CFArrayRef mac_font_create_available_families (void);
46 static Boolean mac_font_equal_in_postscript_name (CTFontRef, CTFontRef);
47 static CTLineRef mac_font_create_line_with_string_and_font (CFStringRef,
48                                                             CTFontRef);
49 static Boolean mac_font_descriptor_supports_languages (CTFontDescriptorRef,
50                                                        CFArrayRef);
51 static CFStringRef mac_font_create_preferred_family_for_attributes (CFDictionaryRef);
52 static CFIndex mac_font_shape (CTFontRef, CFStringRef,
53                                struct mac_glyph_layout *, CFIndex);
54 static CFArrayRef mac_font_copy_default_descriptors_for_language (CFStringRef);
55 static CFStringRef mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef, CFArrayRef);
56 #if USE_CT_GLYPH_INFO
57 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef, CTCharacterCollection,
58                                              CGFontIndex);
59 #endif
61 struct macfont_metrics;
63 /* The actual structure for Mac font that can be cast to struct font.  */
65 struct macfont_info
67   struct font font;
68   CTFontRef macfont;
69   CGFontRef cgfont;
70   ScreenFontRef screen_font;
71   struct macfont_cache *cache;
72   struct macfont_metrics **metrics;
73   short metrics_nrows;
74   bool_bf synthetic_italic_p : 1;
75   bool_bf synthetic_bold_p : 1;
76   unsigned spacing : 2;
77   unsigned antialias : 2;
78   bool_bf color_bitmap_p : 1;
81 /* Values for the `spacing' member in `struct macfont_info'.  */
83 enum
84   {
85     MACFONT_SPACING_PROPORTIONAL,
86     MACFONT_SPACING_MONO,
87     MACFONT_SPACING_SYNTHETIC_MONO,
88   };
90 /* Values for the `antialias' member in `struct macfont_info'.  */
92 enum
93   {
94     MACFONT_ANTIALIAS_DEFAULT,
95     MACFONT_ANTIALIAS_OFF,
96     MACFONT_ANTIALIAS_ON,
97   };
99 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
100 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
101 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
103 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
104 static const CGFloat synthetic_bold_factor = 0.024;
106 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
107                                                         CTFontSymbolicTraits *);
108 static void macfont_store_descriptor_attributes (CTFontDescriptorRef,
109                                                  Lisp_Object);
110 static Lisp_Object macfont_descriptor_entity (CTFontDescriptorRef, Lisp_Object,
111                                               CTFontSymbolicTraits);
112 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
113 static int macfont_glyph_extents (struct font *, CGGlyph,
114                                   struct font_metrics *, CGFloat *, int);
115 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
116 static Boolean macfont_supports_charset_and_languages_p (CTFontDescriptorRef,
117                                                          CFCharacterSetRef,
118                                                          Lisp_Object,
119                                                          CFArrayRef);
120 static Boolean macfont_closest_traits_index_p (CFArrayRef, CTFontSymbolicTraits,
121                                                CFIndex);
122 static CFDataRef mac_font_copy_uvs_table (CTFontRef);
123 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
124                                               const UTF32Char [],
125                                               CGGlyph [], CFIndex);
127 /* From CFData to a lisp string.  Always returns a unibyte string.  */
129 static Lisp_Object
130 cfdata_to_lisp (CFDataRef data)
132   CFIndex len = CFDataGetLength (data);
133   Lisp_Object result = make_uninit_string (len);
135   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
137   return result;
142 /* From CFString to a lisp string.  Returns a unibyte string
143    containing a UTF-8 byte sequence.  */
145 static Lisp_Object
146 cfstring_to_lisp_nodecode (CFStringRef string)
148   Lisp_Object result = Qnil;
149   CFDataRef data;
150   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
152   if (s)
153     {
154       CFIndex i, length = CFStringGetLength (string);
156       for (i = 0; i < length; i++)
157         if (CFStringGetCharacterAtIndex (string, i) == 0)
158           break;
160       if (i == length)
161         return make_unibyte_string (s, strlen (s));
162     }
164   data = CFStringCreateExternalRepresentation (NULL, string,
165                                                kCFStringEncodingUTF8, '?');
166   if (data)
167     {
168       result = cfdata_to_lisp (data);
169       CFRelease (data);
170     }
172   return result;
175 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
176    cfstring_create_with_utf8_cstring, this function preserves NUL
177    characters.  */
179 static CFStringRef
180 cfstring_create_with_string_noencode (Lisp_Object s)
182   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
183                                                 kCFStringEncodingUTF8, false);
185   if (string == NULL)
186     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
187     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
188                                       kCFStringEncodingMacRoman, false);
190   return string;
193 static CFIndex
194 mac_font_get_weight (CTFontRef font)
196   NSFont *nsFont = (NSFont *) font;
198   return [[NSFontManager sharedFontManager] weightOfFont:nsFont];
201 static CGFloat
202 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
204   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
206   return advancement.width;
209 #if !USE_CT_GLYPH_INFO
210 static CGGlyph
211 mac_font_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
212                             CGFontIndex cid)
214   CGGlyph result = kCGFontIndexInvalid;
215   NSFont *nsFont = (NSFont *) font;
216   unichar characters[] = {0xfffd};
217   NSString *string =
218     [NSString stringWithCharacters:characters
219                             length:ARRAYELTS (characters)];
220   NSGlyphInfo *glyphInfo =
221     [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
222                                        collection:collection
223                                        baseString:string];
224   NSDictionary *attributes =
225     [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
226                   glyphInfo,NSGlyphInfoAttributeName,nil];
227   NSTextStorage *textStorage =
228     [[NSTextStorage alloc] initWithString:string
229                                attributes:attributes];
230   NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
231   NSTextContainer *textContainer = [[NSTextContainer alloc] init];
232   NSFont *fontInTextStorage;
234   [layoutManager addTextContainer:textContainer];
235   [textContainer release];
236   [textStorage addLayoutManager:layoutManager];
237   [layoutManager release];
239   /* Force layout.  */
240   (void) [layoutManager glyphRangeForTextContainer:textContainer];
242   fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
243                               effectiveRange:NULL];
244   if (fontInTextStorage == nsFont
245       || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
246     {
247       NSGlyph glyph = [layoutManager glyphAtIndex:0];
249       if (glyph < [nsFont numberOfGlyphs])
250         result = glyph;
251     }
253   [textStorage release];
255   return result;
257 #endif
259 static ScreenFontRef
260 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
262   NSFont *result, *font;
264   font = [NSFont fontWithName:((NSString *) name) size:size];
265   result = [font screenFont];
267   return (ScreenFontRef)[result retain];
271 static Boolean
272 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
273                              CGFloat *descent, CGFloat *leading)
275   NSFont *nsFont = [(NSFont *)font printerFont];
276   NSTextStorage *textStorage;
277   NSLayoutManager *layoutManager;
278   NSTextContainer *textContainer;
279   NSRect usedRect;
280   NSPoint spaceLocation;
281   CGFloat descender;
283   textStorage = [[NSTextStorage alloc] initWithString:@" "];
284   layoutManager = [[NSLayoutManager alloc] init];
285   textContainer = [[NSTextContainer alloc] init];
287   [textStorage setFont:nsFont];
288   [textContainer setLineFragmentPadding:0];
289   [layoutManager setUsesScreenFonts:YES];
291   [layoutManager addTextContainer:textContainer];
292   [textContainer release];
293   [textStorage addLayoutManager:layoutManager];
294   [layoutManager release];
296   if (!(textStorage && layoutManager && textContainer))
297     {
298       [textStorage release];
300       return false;
301     }
303   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
304                                                  effectiveRange:NULL];
305   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
306   [textStorage release];
308   *ascent = spaceLocation.y;
309   *descent = NSHeight (usedRect) - spaceLocation.y;
310   *leading = 0;
311   descender = [nsFont descender];
312   if (- descender < *descent)
313     {
314       *leading = *descent + descender;
315       *descent = - descender;
316     }
318   return true;
321 static CFIndex
322 mac_font_shape_1 (NSFont *font, NSString *string,
323                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
324                   BOOL screen_font_p)
326   NSUInteger i;
327   CFIndex result = 0;
328   NSTextStorage *textStorage;
329   NSLayoutManager *layoutManager;
330   NSTextContainer *textContainer;
331   NSUInteger stringLength;
332   NSPoint spaceLocation;
333   NSUInteger used, numberOfGlyphs;
335   textStorage = [[NSTextStorage alloc] initWithString:string];
336   layoutManager = [[NSLayoutManager alloc] init];
337   textContainer = [[NSTextContainer alloc] init];
339   /* Append a trailing space to measure baseline position.  */
340   [textStorage appendAttributedString:([[[NSAttributedString alloc]
341                                           initWithString:@" "] autorelease])];
342   [textStorage setFont:font];
343   [textContainer setLineFragmentPadding:0];
344   [layoutManager setUsesScreenFonts:screen_font_p];
346   [layoutManager addTextContainer:textContainer];
347   [textContainer release];
348   [textStorage addLayoutManager:layoutManager];
349   [layoutManager release];
351   if (!(textStorage && layoutManager && textContainer))
352     {
353       [textStorage release];
355       return 0;
356     }
358   stringLength = [string length];
360   /* Force layout.  */
361   (void) [layoutManager glyphRangeForTextContainer:textContainer];
363   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
365   /* Remove the appended trailing space because otherwise it may
366      generate a wrong result for a right-to-left text.  */
367   [textStorage beginEditing];
368   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
369   [textStorage endEditing];
370   (void) [layoutManager glyphRangeForTextContainer:textContainer];
372   i = 0;
373   while (i < stringLength)
374     {
375       NSRange range;
376       NSFont *fontInTextStorage =
377         [textStorage attribute:NSFontAttributeName atIndex:i
378                      longestEffectiveRange:&range
379                        inRange:(NSMakeRange (0, stringLength))];
381       if (!(fontInTextStorage == font
382             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
383         break;
384       i = NSMaxRange (range);
385     }
386   if (i < stringLength)
387     /* Make the test `used <= glyph_len' below fail if textStorage
388        contained some fonts other than the specified one.  */
389     used = glyph_len + 1;
390   else
391     {
392       NSRange range = NSMakeRange (0, stringLength);
394       range = [layoutManager glyphRangeForCharacterRange:range
395                                     actualCharacterRange:NULL];
396       numberOfGlyphs = NSMaxRange (range);
397       used = numberOfGlyphs;
398       for (i = 0; i < numberOfGlyphs; i++)
399         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
400           used--;
401     }
403   if (0 < used && used <= glyph_len)
404     {
405       NSUInteger glyphIndex, prevGlyphIndex;
406       unsigned char bidiLevel;
407       NSUInteger *permutation;
408       NSRange compRange, range;
409       CGFloat totalAdvance;
411       glyphIndex = 0;
412       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
413         glyphIndex++;
415       /* For now we assume the direction is not changed within the
416          string.  */
417       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
418                                glyphs:NULL characterIndexes:NULL
419                     glyphInscriptions:NULL elasticBits:NULL
420                            bidiLevels:&bidiLevel];
421       if (bidiLevel & 1)
422         permutation = xmalloc (sizeof (NSUInteger) * used);
423       else
424         permutation = NULL;
426 #define RIGHT_TO_LEFT_P permutation
428       /* Fill the `comp_range' member of struct mac_glyph_layout, and
429          setup a permutation for right-to-left text.  */
430       compRange = NSMakeRange (0, 0);
431       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
432            range.length++)
433         {
434           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
435           NSUInteger characterIndex =
436             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
438           gl->string_index = characterIndex;
440           if (characterIndex >= NSMaxRange (compRange))
441             {
442               compRange.location = NSMaxRange (compRange);
443               do
444                 {
445                   NSRange characterRange =
446                     [string
447                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
449                   compRange.length =
450                     NSMaxRange (characterRange) - compRange.location;
451                   [layoutManager glyphRangeForCharacterRange:compRange
452                                         actualCharacterRange:&characterRange];
453                   characterIndex = NSMaxRange (characterRange) - 1;
454                 }
455               while (characterIndex >= NSMaxRange (compRange));
457               if (RIGHT_TO_LEFT_P)
458                 for (i = 0; i < range.length; i++)
459                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
461               range = NSMakeRange (NSMaxRange (range), 0);
462             }
464           gl->comp_range.location = compRange.location;
465           gl->comp_range.length = compRange.length;
467           while (++glyphIndex < numberOfGlyphs)
468             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
469               break;
470         }
471       if (RIGHT_TO_LEFT_P)
472         for (i = 0; i < range.length; i++)
473           permutation[range.location + i] = NSMaxRange (range) - i - 1;
475       /* Then fill the remaining members.  */
476       glyphIndex = prevGlyphIndex = 0;
477       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
478         glyphIndex++;
480       if (!RIGHT_TO_LEFT_P)
481         totalAdvance = 0;
482       else
483         {
484           NSUInteger nrects;
485           NSRect *glyphRects =
486             [layoutManager
487               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
488               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
489                      inTextContainer:textContainer rectCount:&nrects];
491           totalAdvance = NSMaxX (glyphRects[0]);
492         }
494       for (i = 0; i < used; i++)
495         {
496           struct mac_glyph_layout *gl;
497           NSPoint location;
498           NSUInteger nextGlyphIndex;
499           NSRange glyphRange;
500           NSRect *glyphRects;
501           NSUInteger nrects;
503           if (!RIGHT_TO_LEFT_P)
504             gl = glyph_layouts + i;
505           else
506             {
507               NSUInteger dest = permutation[i];
509               gl = glyph_layouts + dest;
510               if (i < dest)
511                 {
512                   CFIndex tmp = gl->string_index;
514                   gl->string_index = glyph_layouts[i].string_index;
515                   glyph_layouts[i].string_index = tmp;
516                 }
517             }
518           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
520           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
521           gl->baseline_delta = spaceLocation.y - location.y;
523           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
524                nextGlyphIndex++)
525             if (![layoutManager
526                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
527               break;
529           if (!RIGHT_TO_LEFT_P)
530             {
531               CGFloat maxX;
533               if (prevGlyphIndex == 0)
534                 glyphRange = NSMakeRange (0, nextGlyphIndex);
535               else
536                 glyphRange = NSMakeRange (glyphIndex,
537                                           nextGlyphIndex - glyphIndex);
538               glyphRects =
539                 [layoutManager
540                   rectArrayForGlyphRange:glyphRange
541                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
542                          inTextContainer:textContainer rectCount:&nrects];
543               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
544               gl->advance_delta = location.x - totalAdvance;
545               gl->advance = maxX - totalAdvance;
546               totalAdvance = maxX;
547             }
548           else
549             {
550               CGFloat minX;
552               if (nextGlyphIndex == numberOfGlyphs)
553                 glyphRange = NSMakeRange (prevGlyphIndex,
554                                           numberOfGlyphs - prevGlyphIndex);
555               else
556                 glyphRange = NSMakeRange (prevGlyphIndex,
557                                           glyphIndex + 1 - prevGlyphIndex);
558               glyphRects =
559                 [layoutManager
560                   rectArrayForGlyphRange:glyphRange
561                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
562                          inTextContainer:textContainer rectCount:&nrects];
563               minX = min (NSMinX (glyphRects[0]), totalAdvance);
564               gl->advance = totalAdvance - minX;
565               totalAdvance = minX;
566               gl->advance_delta = location.x - totalAdvance;
567             }
569           prevGlyphIndex = glyphIndex + 1;
570           glyphIndex = nextGlyphIndex;
571         }
573       if (RIGHT_TO_LEFT_P)
574         xfree (permutation);
576 #undef RIGHT_TO_LEFT_P
578       result = used;
579     }
580   [textStorage release];
582   return result;
585 static CFIndex
586 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
587                        struct mac_glyph_layout *glyph_layouts,
588                        CFIndex glyph_len)
590   return mac_font_shape_1 ([(NSFont *)font printerFont],
591                            (NSString *) string,
592                            glyph_layouts, glyph_len, YES);
595 static CGColorRef
596 get_cgcolor(unsigned long idx, struct frame *f)
598   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
599   [nsColor set];
600   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
601   NSInteger noc = [nsColor numberOfComponents];
602   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
603   CGColorRef cgColor;
605   [nsColor getComponents: components];
606   cgColor = CGColorCreate (colorSpace, components);
607   xfree (components);
608   return cgColor;
611 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
612   do {                                                                  \
613     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
614     CGContextSetFillColorWithColor (context, refcol_) ;                 \
615     CGColorRelease (refcol_);                                           \
616   } while (0)
617 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
618   do {                                                                  \
619     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
620     CGContextSetFillColorWithColor (context, refcol_);                  \
621     CGColorRelease (refcol_);                                           \
622   } while (0)
623 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
624   do {                                                                  \
625     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
626     CGContextSetStrokeColorWithColor (context, refcol_);                \
627     CGColorRelease (refcol_);                                           \
628   } while (0)
632 /* Mac font driver.  */
634 static struct
636   /* registry name */
637   const char *name;
638   /* characters to distinguish the charset from the others */
639   int uniquifier[6];
640   /* additional constraint by language */
641   CFStringRef lang;
642   /* set on demand */
643   CFCharacterSetRef cf_charset;
644   CFStringRef cf_charset_string;
645 } cf_charset_table[] =
646   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
647     { "iso8859-2", { 0x00A0, 0x010E }},
648     { "iso8859-3", { 0x00A0, 0x0108 }},
649     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
650     { "iso8859-5", { 0x00A0, 0x0401 }},
651     { "iso8859-6", { 0x00A0, 0x060C }},
652     { "iso8859-7", { 0x00A0, 0x0384 }},
653     { "iso8859-8", { 0x00A0, 0x05D0 }},
654     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
655     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
656     { "iso8859-11", { 0x00A0, 0x0E01 }},
657     { "iso8859-13", { 0x00A0, 0x201C }},
658     { "iso8859-14", { 0x00A0, 0x0174 }},
659     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
660     { "iso8859-16", { 0x00A0, 0x0218}},
661     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
662     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
663     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
664     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
665     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
666     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
667     { "cns11643.1992-3", { 0x201A9 }},
668     { "cns11643.1992-4", { 0x20057 }},
669     { "cns11643.1992-5", { 0x20000 }},
670     { "cns11643.1992-6", { 0x20003 }},
671     { "cns11643.1992-7", { 0x20055 }},
672     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
673     { "jisx0212.1990-0", { 0x4E44 }},
674     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
675     { "jisx0213.2000-2", { 0xFA49 }},
676     { "jisx0213.2004-1", { 0x20B9F }},
677     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
678     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
679     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
680     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
681     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
682     { "unicode-sip", { 0x20000 }},
683     { NULL }
684   };
686 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
687 static const struct
689   CFStringRef language;
690   CFStringRef font_names[3];
691 } macfont_language_default_font_names[] = {
692   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
693                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
694                     NULL }},
695   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
696                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
697                     NULL }},
698   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
699                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
700                          NULL }},
701   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
702                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
703                          NULL }},
704   { NULL }
706 #endif
708 static CGFloat macfont_antialias_threshold;
710 void
711 macfont_update_antialias_threshold (void)
713   int threshold;
714   Boolean valid_p;
716   threshold =
717     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
718                                      kCFPreferencesCurrentApplication,
719                                      &valid_p);
720   if (valid_p)
721     macfont_antialias_threshold = threshold;
724 static inline Lisp_Object
725 macfont_intern_prop_cfstring (CFStringRef cfstring)
727   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
729   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
732 static inline CFIndex
733 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
735   if (c < 0x10000)
736     {
737       unichars[0] = c;
739       return 1;
740     }
741   else
742     {
743       c -= 0x10000;
744       unichars[0] = (c >> 10) + 0xD800;
745       unichars[1] = (c & 0x3FF) + 0xDC00;
747       return 2;
748     }
751 static Boolean
752 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
753                                          CTFontSymbolicTraits *sym_traits)
755   SInt64 sint64_value;
757   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
758      OS X 10.6 when the value is greater than or equal to 1 << 31.  */
759   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
760     {
761       *sym_traits = (CTFontSymbolicTraits) sint64_value;
763       return true;
764     }
766   return false;
769 static CGFloat
770 mac_font_descriptor_get_adjusted_weight (CTFontDescriptorRef desc, CGFloat val)
772   long percent_val = lround (val * 100);
774   if (percent_val == -40)
775     {
776       CTFontRef font = NULL;
777       CFStringRef name =
778         CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
780       if (name)
781         {
782           font = CTFontCreateWithName (name, 0, NULL);
783           CFRelease (name);
784         }
785       if (font)
786         {
787           CFIndex weight = mac_font_get_weight (font);
789           /* Workaround for crash when displaying Oriya characters
790              with Arial Unicode MS on OS X 10.11.  */
791           if (weight == 5)
792             val = 0;
793           CFRelease (font);
794         }
795     }
797   return val;
800 static void
801 macfont_store_descriptor_attributes (CTFontDescriptorRef desc,
802                                      Lisp_Object spec_or_entity)
804   CFStringRef str;
805   CFDictionaryRef dict;
806   CFNumberRef num;
807   CGFloat floatval;
809   str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
810   if (str)
811     {
812       ASET (spec_or_entity, FONT_FAMILY_INDEX,
813             macfont_intern_prop_cfstring (str));
814       CFRelease (str);
815     }
816   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
817   if (dict)
818     {
819       struct {
820         enum font_property_index index;
821         CFStringRef trait;
822         CGPoint points[6];
823         CGFloat (*adjust_func) (CTFontDescriptorRef, CGFloat);
824       } numeric_traits[] =
825           {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
826             {{-0.4, 50},        /* light */
827              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
828              {0, 100},          /* normal */
829              {0.24, 140},       /* (semi-bold + normal) / 2 */
830              {0.4, 200},        /* bold */
831              {CGFLOAT_MAX, CGFLOAT_MAX}},
832             mac_font_descriptor_get_adjusted_weight},
833            {FONT_SLANT_INDEX, kCTFontSlantTrait,
834             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL},
835            {FONT_WIDTH_INDEX, kCTFontWidthTrait,
836             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL}};
837       int i;
839       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
840         {
841           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
842           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
843             {
844               CGPoint *point = numeric_traits[i].points;
846               if (numeric_traits[i].adjust_func)
847                 floatval = (*numeric_traits[i].adjust_func) (desc, floatval);
848               while (point->x < floatval)
849                 point++;
850               if (point == numeric_traits[i].points)
851                 point++;
852               else if (point->x == CGFLOAT_MAX)
853                 point--;
854               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
855                                            * ((point->y - (point - 1)->y)
856                                               / (point->x - (point - 1)->x)));
857               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
858                               make_number (lround (floatval)));
859             }
860         }
862       num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
863       if (num)
864         {
865           CTFontSymbolicTraits sym_traits;
866           int spacing;
868           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
869           spacing = (sym_traits & kCTFontTraitMonoSpace
870                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
871           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
872         }
874       CFRelease (dict);
875     }
876   num = CTFontDescriptorCopyAttribute (desc, kCTFontSizeAttribute);
877   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
878     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
879   else
880     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
881   if (num)
882     CFRelease (num);
885 static Lisp_Object
886 macfont_descriptor_entity (CTFontDescriptorRef desc, Lisp_Object extra,
887                            CTFontSymbolicTraits synth_sym_traits)
889   Lisp_Object entity;
890   CFDictionaryRef dict;
891   CTFontSymbolicTraits sym_traits = 0;
892   CFStringRef name;
894   entity = font_make_entity ();
896   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
897   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
899   macfont_store_descriptor_attributes (desc, entity);
901   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
902   if (dict)
903     {
904       CFNumberRef num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
906       if (num)
907         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
908       CFRelease (dict);
909     }
910   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
911     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
912   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
913   name = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
914   font_put_extra (entity, QCfont_entity,
915                   make_save_ptr_int ((void *) name, sym_traits));
916   if (synth_sym_traits & kCTFontTraitItalic)
917     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
918                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
919   if (synth_sym_traits & kCTFontTraitBold)
920     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
921                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
922   if (synth_sym_traits & kCTFontTraitMonoSpace)
923     ASET (entity, FONT_SPACING_INDEX,
924           make_number (FONT_SPACING_SYNTHETIC_MONO));
926   return entity;
929 /* Cache for font family name symbols vs CFStrings.  A value of nil
930 means the cache has been invalidated.  Otherwise the value is a Lisp
931 hash table whose keys are symbols and the value for a key is either
932 nil (no corresponding family name) or a Lisp save value wrapping the
933 corresponding family name in CFString.  */
935 static Lisp_Object macfont_family_cache;
937 static void
938 macfont_invalidate_family_cache (void)
940   if (HASH_TABLE_P (macfont_family_cache))
941     {
942       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
943       ptrdiff_t i, size = HASH_TABLE_SIZE (h);
945       for (i = 0; i < size; ++i)
946         if (!NILP (HASH_HASH (h, i)))
947           {
948             Lisp_Object value = HASH_VALUE (h, i);
950             if (SAVE_VALUEP (value))
951               CFRelease (XSAVE_POINTER (value, 0));
952           }
953       macfont_family_cache = Qnil;
954     }
957 static bool
958 macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
960   if (HASH_TABLE_P (macfont_family_cache))
961     {
962       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
963       ptrdiff_t i = hash_lookup (h, symbol, NULL);
965       if (i >= 0)
966         {
967           Lisp_Object value = HASH_VALUE (h, i);
969           *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
971           return true;
972         }
973     }
975   return false;
978 static void
979 macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
981   struct Lisp_Hash_Table *h;
982   ptrdiff_t i;
983   EMACS_UINT hash;
984   Lisp_Object value;
986   if (!HASH_TABLE_P (macfont_family_cache))
987     macfont_family_cache = CALLN (Fmake_hash_table, QCtest, Qeq);
989   h = XHASH_TABLE (macfont_family_cache);
990   i = hash_lookup (h, symbol, &hash);
991   value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
992   if (i >= 0)
993     {
994       Lisp_Object old_value = HASH_VALUE (h, i);
996       if (SAVE_VALUEP (old_value))
997         CFRelease (XSAVE_POINTER (old_value, 0));
998       set_hash_value_slot (h, i, value);
999     }
1000   else
1001     hash_put (h, symbol, value, hash);
1004 /* Cache of all the available font family names except "LastResort"
1005 and those start with ".".  NULL means the cache has been invalidated.
1006 Otherwise, the value is CFArray of CFStrings and the elements are
1007 sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
1008 OS X 10.6 and later).  */
1010 static CFArrayRef macfont_available_families_cache = NULL;
1012 static void
1013 macfont_invalidate_available_families_cache (void)
1015   if (macfont_available_families_cache)
1016     {
1017       CFRelease (macfont_available_families_cache);
1018       macfont_available_families_cache = NULL;
1019     }
1022 static void
1023 macfont_handle_font_change_notification (CFNotificationCenterRef center,
1024                                          void *observer,
1025                                          CFStringRef name, const void *object,
1026                                          CFDictionaryRef userInfo)
1028   macfont_invalidate_family_cache ();
1029   macfont_invalidate_available_families_cache ();
1032 static void
1033 macfont_init_font_change_handler (void)
1035   static bool initialized = false;
1037   if (initialized)
1038     return;
1040   initialized = true;
1041   CFNotificationCenterAddObserver
1042     (CFNotificationCenterGetLocalCenter (), NULL,
1043      macfont_handle_font_change_notification,
1044      kCTFontManagerRegisteredFontsChangedNotification,
1045      NULL, CFNotificationSuspensionBehaviorCoalesce);
1048 static CFArrayRef
1049 macfont_copy_available_families_cache (void)
1051   macfont_init_font_change_handler ();
1053   if (macfont_available_families_cache == NULL)
1054     macfont_available_families_cache = mac_font_create_available_families ();
1056   return (macfont_available_families_cache
1057           ? CFRetain (macfont_available_families_cache) : NULL);
1060 static CFStringRef
1061 macfont_create_family_with_symbol (Lisp_Object symbol)
1063   CFStringRef result = NULL, family_name;
1064   CFDictionaryRef attributes = NULL;
1065   CTFontDescriptorRef pat_desc = NULL;
1067   if (macfont_get_family_cache_if_present (symbol, &result))
1068     return result ? CFRetain (result) : NULL;
1070   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1071   if (family_name)
1072     {
1073       attributes =
1074         CFDictionaryCreate (NULL,
1075                             (const void **) &kCTFontFamilyNameAttribute,
1076                             (const void **) &family_name, 1,
1077                             &kCFTypeDictionaryKeyCallBacks,
1078                             &kCFTypeDictionaryValueCallBacks);
1079       CFRelease (family_name);
1080     }
1081   if (attributes)
1082     {
1083       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
1084       CFRelease (attributes);
1085     }
1086   if (pat_desc)
1087     {
1088       CTFontDescriptorRef desc =
1089         CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
1091       if (desc)
1092         {
1093           result =
1094             CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
1095           CFRelease (desc);
1096         }
1097       macfont_set_family_cache (symbol, result);
1098       CFRelease (pat_desc);
1099     }
1101   return result;
1104 #define WIDTH_FRAC_BITS         (4)
1105 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1107 struct macfont_metrics
1109   unsigned char lbearing_low, rbearing_low;
1110   signed lbearing_high : 4, rbearing_high : 4;
1111   unsigned char ascent_low, descent_low;
1112   signed ascent_high : 4, descent_high : 4;
1114   /* These two members are used for fixed-point representation of
1115      glyph width.  The `width_int' member is an integer that is
1116      closest to the width.  The `width_frac' member is the fractional
1117      adjustment representing a value in [-.5, .5], multiplied by
1118      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1119      the advance delta for centering instead of the glyph width.  */
1120   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1123 #define METRICS_VALUE(metrics, member)                          \
1124   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1125 #define METRICS_SET_VALUE(metrics, member, value)                   \
1126   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
1127     (metrics)->member##_high = tmp >> 8;} while (0)
1129 enum metrics_status
1131   METRICS_INVALID = -1,    /* metrics entry is invalid */
1132   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1135 #define METRICS_STATUS(metrics)                                         \
1136   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1137 #define METRICS_SET_STATUS(metrics, status)                     \
1138   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1139     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1141 #define METRICS_NCOLS_PER_ROW   (128)
1142 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1143 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1145 static int
1146 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1147                        struct font_metrics *metrics, CGFloat *advance_delta,
1148                        int force_integral_p)
1150   struct macfont_info *macfont_info = (struct macfont_info *) font;
1151   CTFontRef macfont = macfont_info->macfont;
1152   int row, col;
1153   struct macfont_metrics *cache;
1154   int width;
1156   row = glyph / METRICS_NCOLS_PER_ROW;
1157   col = glyph % METRICS_NCOLS_PER_ROW;
1158   if (row >= macfont_info->metrics_nrows)
1159     {
1160       macfont_info->metrics =
1161         xrealloc (macfont_info->metrics,
1162                   sizeof (struct macfont_metrics *) * (row + 1));
1163       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1164               (sizeof (struct macfont_metrics *)
1165                * (row + 1 - macfont_info->metrics_nrows)));
1166       macfont_info->metrics_nrows = row + 1;
1167     }
1168   if (macfont_info->metrics[row] == NULL)
1169     {
1170       struct macfont_metrics *new;
1171       int i;
1173       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1174       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1175         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1176       macfont_info->metrics[row] = new;
1177     }
1178   cache = macfont_info->metrics[row] + col;
1180   if (METRICS_STATUS (cache) == METRICS_INVALID)
1181     {
1182       CGFloat fwidth;
1184       if (macfont_info->screen_font)
1185         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1186       else
1187         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1189       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1190          advance delta value.  */
1191       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1192         fwidth = (font->pixel_size - fwidth) / 2;
1193       cache->width_int = lround (fwidth);
1194       cache->width_frac = lround ((fwidth - cache->width_int)
1195                                   * WIDTH_FRAC_SCALE);
1196       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1197     }
1198   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1199     width = font->pixel_size;
1200   else
1201     width = cache->width_int;
1203   if (metrics)
1204     {
1205       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1206         {
1207           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1209           if (macfont_info->synthetic_italic_p)
1210             {
1211               /* We assume the members a, b, c, and d in
1212                  synthetic_italic_atfm are non-negative.  */
1213               bounds.origin =
1214                 CGPointApplyAffineTransform (bounds.origin,
1215                                              synthetic_italic_atfm);
1216               bounds.size =
1217                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1218             }
1219           if (macfont_info->synthetic_bold_p && ! force_integral_p)
1220             {
1221               CGFloat d = - synthetic_bold_factor * CTFontGetSize (macfont) / 2;
1223               bounds = CGRectInset (bounds, d, d);
1224             }
1225           switch (macfont_info->spacing)
1226             {
1227             case MACFONT_SPACING_PROPORTIONAL:
1228               bounds.origin.x += - (cache->width_frac
1229                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1230               break;
1231             case MACFONT_SPACING_MONO:
1232               break;
1233             case MACFONT_SPACING_SYNTHETIC_MONO:
1234               bounds.origin.x += (cache->width_int
1235                                   + (cache->width_frac
1236                                      / (CGFloat) WIDTH_FRAC_SCALE));
1237               break;
1238             }
1239           if (bounds.size.width > 0)
1240             {
1241               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1242               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1243                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1244             }
1245           bounds = CGRectIntegral (bounds);
1246           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1247           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1248           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1249           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1250         }
1251       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1252       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1253       metrics->width = width;
1254       metrics->ascent = METRICS_VALUE (cache, ascent);
1255       metrics->descent = METRICS_VALUE (cache, descent);
1256     }
1258   if (advance_delta)
1259     {
1260       switch (macfont_info->spacing)
1261         {
1262         case MACFONT_SPACING_PROPORTIONAL:
1263           *advance_delta = (force_integral_p ? 0
1264                             : - (cache->width_frac
1265                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1266           break;
1267         case MACFONT_SPACING_MONO:
1268           *advance_delta = 0;
1269           break;
1270         case MACFONT_SPACING_SYNTHETIC_MONO:
1271           *advance_delta = (force_integral_p ? cache->width_int
1272                             : (cache->width_int
1273                                + (cache->width_frac
1274                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1275           break;
1276         }
1277     }
1279   return width;
1282 static CFMutableDictionaryRef macfont_cache_dictionary;
1284 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1285    equal to the number of rows that are invalid as BMP (i.e., from
1286    U+D800 to U+DFFF).  */
1287 #define ROW_PERM_OFFSET (8)
1289 /* The number of glyphs that can be stored in a value for a single
1290    entry of CFDictionary.  */
1291 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1293 struct macfont_cache
1295   int reference_count;
1296   CFCharacterSetRef cf_charset;
1297   struct {
1298     /* The cached glyph for a BMP character c is stored in
1299        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1300        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1301     unsigned char row_nkeys_or_perm[256];
1302     CGGlyph **matrix;
1304     /* Number of rows for which the BMP cache is allocated so far.
1305        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1306     int nrows;
1308     /* The cached glyph for a character c is stored as the (c %
1309        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1310        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1311        not stored here if row_nkeys_or_perm[c / 256] >=
1312        ROW_PERM_OFFSET.  */
1313     CFMutableDictionaryRef dictionary;
1314   } glyph;
1316   struct {
1317     /* UVS (Unicode Variation Sequence) subtable data, which is of
1318        type CFDataRef if available.  NULL means it is not initialized
1319        yet.  kCFNull means the subtable is not found and there is no
1320        suitable fallback table for this font.  */
1321     CFTypeRef table;
1323     /* Character collection specifying the destination of the mapping
1324        provided by `table' above.  If `table' is obtained from the UVS
1325        subtable in the font cmap table, then the value of this member
1326        should be kCTCharacterCollectionIdentityMapping.  */
1327     CTCharacterCollection collection;
1328   } uvs;
1331 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1332 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1333 static void macfont_release_cache (struct macfont_cache *);
1334 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1335 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1336 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1337 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1338                                           CTCharacterCollection, CGFontIndex);
1339 static CFDataRef macfont_get_uvs_table (struct font *, CTCharacterCollection *);
1341 static struct macfont_cache *
1342 macfont_lookup_cache (CFStringRef key)
1344   struct macfont_cache *cache;
1346   if (macfont_cache_dictionary == NULL)
1347     {
1348       macfont_cache_dictionary =
1349         CFDictionaryCreateMutable (NULL, 0,
1350                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1351       cache = NULL;
1352     }
1353   else
1354     cache = ((struct macfont_cache *)
1355              CFDictionaryGetValue (macfont_cache_dictionary, key));
1357   if (cache == NULL)
1358     {
1359       CTFontRef macfont = CTFontCreateWithName (key, 0, NULL);
1361       if (macfont)
1362         {
1363           cache = xzalloc (sizeof (struct macfont_cache));
1364           /* Treat the LastResort font as if it contained glyphs for
1365              all characters.  This may look too rough, but neither
1366              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1367              for this font is correct for non-BMP characters on Mac OS
1368              X 10.5, anyway.  */
1369           if (CFEqual (key, CFSTR ("LastResort")))
1370             {
1371               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1373               cache->cf_charset =
1374                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1375             }
1376           if (cache->cf_charset == NULL)
1377             cache->cf_charset = CTFontCopyCharacterSet (macfont);
1378           CFDictionaryAddValue (macfont_cache_dictionary, key,
1379                                 (const void *) cache);
1380           CFRelease (macfont);
1381         }
1382     }
1384   return cache;
1387 static struct macfont_cache *
1388 macfont_retain_cache (struct macfont_cache *cache)
1390   cache->reference_count++;
1392   return cache;
1395 static void
1396 macfont_release_cache (struct macfont_cache *cache)
1398   if (--cache->reference_count == 0)
1399     {
1400       int i;
1402       for (i = 0; i < cache->glyph.nrows; i++)
1403         xfree (cache->glyph.matrix[i]);
1404       xfree (cache->glyph.matrix);
1405       if (cache->glyph.dictionary)
1406         CFRelease (cache->glyph.dictionary);
1407       memset (&cache->glyph, 0, sizeof (cache->glyph));
1408       if (cache->uvs.table)
1409         CFRelease (cache->uvs.table);
1410       memset (&cache->uvs, 0, sizeof (cache->uvs));
1411     }
1414 static CFCharacterSetRef
1415 macfont_get_cf_charset (struct font *font)
1417   struct macfont_info *macfont_info = (struct macfont_info *) font;
1419   return macfont_info->cache->cf_charset;
1422 static CFCharacterSetRef
1423 macfont_get_cf_charset_for_name (CFStringRef name)
1425   struct macfont_cache *cache = macfont_lookup_cache (name);
1427   return cache->cf_charset;
1430 static CGGlyph
1431 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1433   struct macfont_info *macfont_info = (struct macfont_info *) font;
1434   CTFontRef macfont = macfont_info->macfont;
1435   struct macfont_cache *cache = macfont_info->cache;
1437   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1438     {
1439       int row = c / 256;
1440       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1442       if (nkeys_or_perm < ROW_PERM_OFFSET)
1443         {
1444           UniChar unichars[256], ch;
1445           CGGlyph *glyphs;
1446           int i, len;
1447           int nrows;
1448           dispatch_queue_t queue;
1449           dispatch_group_t group = NULL;
1451           if (row != 0)
1452             {
1453               CFMutableDictionaryRef dictionary;
1454               uintptr_t key, value;
1455               int nshifts;
1456               CGGlyph glyph;
1458               if (cache->glyph.dictionary == NULL)
1459                 cache->glyph.dictionary =
1460                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1461               dictionary = cache->glyph.dictionary;
1462               key = c / NGLYPHS_IN_VALUE;
1463               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1464               value = ((uintptr_t)
1465                        CFDictionaryGetValue (dictionary, (const void *) key));
1466               glyph = (value >> nshifts);
1467               if (glyph)
1468                 return glyph;
1470               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1471                 {
1472                   ch = c;
1473                   if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1474                       || glyph == 0)
1475                     glyph = kCGFontIndexInvalid;
1477                   if (value == 0)
1478                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1479                   value |= ((uintptr_t) glyph << nshifts);
1480                   CFDictionarySetValue (dictionary, (const void *) key,
1481                                         (const void *) value);
1483                   return glyph;
1484                 }
1486               queue =
1487                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1488               group = dispatch_group_create ();
1489               dispatch_group_async (group, queue, ^{
1490                   int nkeys;
1491                   uintptr_t key;
1492                   nkeys = nkeys_or_perm;
1493                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1494                     if (CFDictionaryContainsKey (dictionary,
1495                                                  (const void *) key))
1496                       {
1497                         CFDictionaryRemoveValue (dictionary,
1498                                                  (const void *) key);
1499                         if (--nkeys == 0)
1500                           break;
1501                       }
1502                 });
1503             }
1505           len = 0;
1506           for (i = 0; i < 256; i++)
1507             {
1508               ch = row * 256 + i;
1509               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1510                 unichars[len++] = ch;
1511             }
1513           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1514           if (len > 0)
1515             {
1516               CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1517               while (i > len)
1518                 {
1519                   int next = unichars[len - 1] % 256;
1521                   while (--i > next)
1522                     glyphs[i] = kCGFontIndexInvalid;
1524                   len--;
1525                   glyphs[i] = glyphs[len];
1526                   if (len == 0)
1527                     break;
1528                 }
1529             }
1530           if (i > len)
1531             while (i-- > 0)
1532               glyphs[i] = kCGFontIndexInvalid;
1534           nrows = cache->glyph.nrows;
1535           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1536           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1537           nrows++;
1538           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1539                                           sizeof (CGGlyph *) * nrows);
1540           cache->glyph.matrix[nrows - 1] = glyphs;
1541           cache->glyph.nrows = nrows;
1543           if (group)
1544             {
1545               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1546               dispatch_release (group);
1547             }
1548         }
1550       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1551     }
1552   else
1553     {
1554       uintptr_t key, value;
1555       int nshifts;
1556       CGGlyph glyph;
1558       if (cache->glyph.dictionary == NULL)
1559         cache->glyph.dictionary =
1560           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1561       key = c / NGLYPHS_IN_VALUE;
1562       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1563       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1564                                                 (const void *) key);
1565       glyph = (value >> nshifts);
1566       if (glyph == 0)
1567         {
1568           UniChar unichars[2];
1569           CGGlyph glyphs[2];
1570           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1572           if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1573             glyph = glyphs[0];
1574           if (glyph == 0)
1575             glyph = kCGFontIndexInvalid;
1577           value |= ((uintptr_t) glyph << nshifts);
1578           CFDictionarySetValue (cache->glyph.dictionary,
1579                                 (const void *) key, (const void *) value);
1580         }
1582       return glyph;
1583     }
1586 static CGGlyph
1587 macfont_get_glyph_for_cid (struct font *font, CTCharacterCollection collection,
1588                            CGFontIndex cid)
1590   struct macfont_info *macfont_info = (struct macfont_info *) font;
1591   CTFontRef macfont = macfont_info->macfont;
1593   /* Cache it? */
1594   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1597 static CFDataRef
1598 macfont_get_uvs_table (struct font *font, CTCharacterCollection *collection)
1600   struct macfont_info *macfont_info = (struct macfont_info *) font;
1601   CTFontRef macfont = macfont_info->macfont;
1602   struct macfont_cache *cache = macfont_info->cache;
1603   CFDataRef result = NULL;
1605   if (cache->uvs.table == NULL)
1606     {
1607       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1608       CTCharacterCollection uvs_collection =
1609         kCTCharacterCollectionIdentityMapping;
1611       if (uvs_table == NULL
1612           && mac_font_get_glyph_for_cid (macfont,
1613                                          kCTCharacterCollectionAdobeJapan1,
1614                                          6480) != kCGFontIndexInvalid)
1615         {
1616           /* If the glyph for U+4E55 is accessible via its CID 6480,
1617              then we use the Adobe-Japan1 UVS table, which maps a
1618              variation sequence to a CID, as a fallback.  */
1619           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1621           if (mac_uvs_table_adobe_japan1 == NULL)
1622             mac_uvs_table_adobe_japan1 =
1623               CFDataCreateWithBytesNoCopy (NULL,
1624                                            mac_uvs_table_adobe_japan1_bytes,
1625                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1626                                            kCFAllocatorNull);
1627           if (mac_uvs_table_adobe_japan1)
1628             {
1629               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1630               uvs_collection = kCTCharacterCollectionAdobeJapan1;
1631             }
1632         }
1633       if (uvs_table == NULL)
1634         cache->uvs.table = kCFNull;
1635       else
1636         cache->uvs.table = uvs_table;
1637       cache->uvs.collection = uvs_collection;
1638     }
1640   if (cache->uvs.table != kCFNull)
1641     {
1642       result = cache->uvs.table;
1643       *collection = cache->uvs.collection;
1644     }
1646   return result;
1649 static Lisp_Object macfont_get_cache (struct frame *);
1650 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1651 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1652 static Lisp_Object macfont_list_family (struct frame *);
1653 static void macfont_free_entity (Lisp_Object);
1654 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1655 static void macfont_close (struct font *);
1656 static int macfont_has_char (Lisp_Object, int);
1657 static unsigned macfont_encode_char (struct font *, int);
1658 static void macfont_text_extents (struct font *, unsigned int *, int,
1659                                   struct font_metrics *);
1660 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1661 static Lisp_Object macfont_shape (Lisp_Object);
1662 static int macfont_variation_glyphs (struct font *, int c,
1663                                      unsigned variations[256]);
1664 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1666 static struct font_driver macfont_driver =
1667   {
1668     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1669     0,                          /* case insensitive */
1670     macfont_get_cache,
1671     macfont_list,
1672     macfont_match,
1673     macfont_list_family,
1674     macfont_free_entity,
1675     macfont_open,
1676     macfont_close,
1677     NULL,                       /* prepare_face */
1678     NULL,                       /* done_face */
1679     macfont_has_char,
1680     macfont_encode_char,
1681     macfont_text_extents,
1682     macfont_draw,
1683     NULL,                       /* get_bitmap */
1684     NULL,                       /* free_bitmap */
1685     NULL,                       /* anchor_point */
1686     NULL,                       /* otf_capability */
1687     NULL,                       /* otf_drive */
1688     NULL,                       /* start_for_frame */
1689     NULL,                       /* end_for_frame */
1690     macfont_shape,
1691     NULL,                       /* check */
1692     macfont_variation_glyphs,
1693     macfont_filter_properties,
1694   };
1696 static Lisp_Object
1697 macfont_get_cache (struct frame * f)
1699   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1701   return (dpyinfo->name_list_element);
1704 static int
1705 macfont_get_charset (Lisp_Object registry)
1707   char *str = SSDATA (SYMBOL_NAME (registry));
1708   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1709   Lisp_Object regexp;
1710   int i, j;
1712   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1713     {
1714       if (str[i] == '.')
1715         re[j++] = '\\';
1716       else if (str[i] == '*')
1717         re[j++] = '.';
1718       re[j] = str[i];
1719       if (re[j] == '?')
1720         re[j] = '.';
1721     }
1722   re[j] = '\0';
1723   regexp = make_unibyte_string (re, j);
1724   for (i = 0; cf_charset_table[i].name; i++)
1725     if (fast_c_string_match_ignore_case
1726         (regexp, cf_charset_table[i].name,
1727          strlen (cf_charset_table[i].name)) >= 0)
1728       break;
1729   if (! cf_charset_table[i].name)
1730     return -1;
1731   if (! cf_charset_table[i].cf_charset)
1732     {
1733       int *uniquifier = cf_charset_table[i].uniquifier;
1734       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1735       CFIndex count = 0;
1736       CFStringRef string;
1737       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1739       if (! charset)
1740         return -1;
1741       for (j = 0; uniquifier[j]; j++)
1742         {
1743           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1744                                                         unichars + count);
1745           CFCharacterSetAddCharactersInRange (charset,
1746                                               CFRangeMake (uniquifier[j], 1));
1747         }
1749       string = CFStringCreateWithCharacters (NULL, unichars, count);
1750       if (! string)
1751         {
1752           CFRelease (charset);
1753           return -1;
1754         }
1755       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1756                                                                  charset);
1757       CFRelease (charset);
1758       /* CFCharacterSetCreateWithCharactersInString does not handle
1759          surrogate pairs properly as of Mac OS X 10.5.  */
1760       cf_charset_table[i].cf_charset_string = string;
1761     }
1762   return i;
1765 struct OpenTypeSpec
1767   Lisp_Object script;
1768   unsigned int script_tag, langsys_tag;
1769   int nfeatures[2];
1770   unsigned int *features[2];
1773 #define OTF_SYM_TAG(SYM, TAG)                               \
1774   do {                                                      \
1775     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1776     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1777   } while (0)
1779 #define OTF_TAG_STR(TAG, P)                     \
1780   do {                                          \
1781     (P)[0] = (char) (TAG >> 24);                \
1782     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1783     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1784     (P)[3] = (char) (TAG & 0xFF);               \
1785     (P)[4] = '\0';                              \
1786   } while (0)
1788 static struct OpenTypeSpec *
1789 macfont_get_open_type_spec (Lisp_Object otf_spec)
1791   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1792   Lisp_Object val;
1793   int i, j;
1794   bool negative;
1796   if (! spec)
1797     return NULL;
1798   spec->script = XCAR (otf_spec);
1799   if (! NILP (spec->script))
1800     {
1801       OTF_SYM_TAG (spec->script, spec->script_tag);
1802       val = assq_no_quit (spec->script, Votf_script_alist);
1803       if (CONSP (val) && SYMBOLP (XCDR (val)))
1804         spec->script = XCDR (val);
1805       else
1806         spec->script = Qnil;
1807     }
1808   else
1809     spec->script_tag = 0x44464C54;      /* "DFLT" */
1810   otf_spec = XCDR (otf_spec);
1811   spec->langsys_tag = 0;
1812   if (! NILP (otf_spec))
1813     {
1814       val = XCAR (otf_spec);
1815       if (! NILP (val))
1816         OTF_SYM_TAG (val, spec->langsys_tag);
1817       otf_spec = XCDR (otf_spec);
1818     }
1819   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1820   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1821     {
1822       Lisp_Object len;
1824       val = XCAR (otf_spec);
1825       if (NILP (val))
1826         continue;
1827       len = Flength (val);
1828       spec->features[i] =
1829         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1830          ? 0
1831          : malloc (XINT (len) * sizeof *spec->features[i]));
1832       if (! spec->features[i])
1833         {
1834           if (i > 0 && spec->features[0])
1835             free (spec->features[0]);
1836           free (spec);
1837           return NULL;
1838         }
1839       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1840         {
1841           if (NILP (XCAR (val)))
1842             negative = 1;
1843           else
1844             {
1845               unsigned int tag;
1847               OTF_SYM_TAG (XCAR (val), tag);
1848               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1849             }
1850         }
1851       spec->nfeatures[i] = j;
1852     }
1853   return spec;
1856 static CFMutableDictionaryRef
1857 macfont_create_attributes_with_spec (Lisp_Object spec)
1859   Lisp_Object tmp, extra;
1860   CFMutableArrayRef langarray = NULL;
1861   CFCharacterSetRef charset = NULL;
1862   CFStringRef charset_string = NULL;
1863   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1864   Lisp_Object script = Qnil;
1865   Lisp_Object registry;
1866   int cf_charset_idx, i;
1867   struct OpenTypeSpec *otspec = NULL;
1868   struct {
1869     enum font_property_index index;
1870     CFStringRef trait;
1871     CGPoint points[6];
1872   } numeric_traits[] =
1873       {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1874         {{-0.4, 50},            /* light */
1875          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1876          {0, 100},              /* normal */
1877          {0.24, 140},           /* (semi-bold + normal) / 2 */
1878          {0.4, 200},            /* bold */
1879          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1880        {FONT_SLANT_INDEX, kCTFontSlantTrait,
1881         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1882        {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1883         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1885   registry = AREF (spec, FONT_REGISTRY_INDEX);
1886   if (NILP (registry)
1887       || EQ (registry, Qascii_0)
1888       || EQ (registry, Qiso10646_1)
1889       || EQ (registry, Qunicode_bmp))
1890     cf_charset_idx = -1;
1891   else
1892     {
1893       CFStringRef lang;
1895       cf_charset_idx = macfont_get_charset (registry);
1896       if (cf_charset_idx < 0)
1897         goto err;
1898       charset = cf_charset_table[cf_charset_idx].cf_charset;
1899       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1900       lang = cf_charset_table[cf_charset_idx].lang;
1901       if (lang)
1902         {
1903           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1904           if (! langarray)
1905             goto err;
1906           CFArrayAppendValue (langarray, lang);
1907         }
1908     }
1910   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1911        CONSP (extra); extra = XCDR (extra))
1912     {
1913       Lisp_Object key, val;
1915       tmp = XCAR (extra);
1916       key = XCAR (tmp), val = XCDR (tmp);
1917       if (EQ (key, QClang))
1918         {
1919           if (! langarray)
1920             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1921           if (! langarray)
1922             goto err;
1923           if (SYMBOLP (val))
1924             val = list1 (val);
1925           for (; CONSP (val); val = XCDR (val))
1926             if (SYMBOLP (XCAR (val)))
1927               {
1928                 CFStringRef lang =
1929                   cfstring_create_with_string_noencode (SYMBOL_NAME
1930                                                         (XCAR (val)));
1932                 if (lang == NULL)
1933                   goto err;
1934                 CFArrayAppendValue (langarray, lang);
1935                 CFRelease (lang);
1936               }
1937         }
1938       else if (EQ (key, QCotf))
1939         {
1940           otspec = macfont_get_open_type_spec (val);
1941           if (! otspec)
1942             goto err;
1943           script = otspec->script;
1944         }
1945       else if (EQ (key, QCscript))
1946         script = val;
1947     }
1949   if (! NILP (script) && ! charset)
1950     {
1951       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1953       if (CONSP (chars) && CONSP (CDR (chars)))
1954         {
1955           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1956           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1958           if (! string || !cs)
1959             {
1960               if (string)
1961                 CFRelease (string);
1962               else if (cs)
1963                 CFRelease (cs);
1964               goto err;
1965             }
1966           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1967             if (CHARACTERP (XCAR (chars)))
1968               {
1969                 UniChar unichars[2];
1970                 CFIndex count =
1971                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1972                                                        unichars);
1973                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1975                 CFStringAppendCharacters (string, unichars, count);
1976                 CFCharacterSetAddCharactersInRange (cs, range);
1977               }
1978           charset = cs;
1979           /* CFCharacterSetCreateWithCharactersInString does not
1980              handle surrogate pairs properly as of Mac OS X 10.5.  */
1981           charset_string = string;
1982         }
1983     }
1985   attributes = CFDictionaryCreateMutable (NULL, 0,
1986                                           &kCFTypeDictionaryKeyCallBacks,
1987                                           &kCFTypeDictionaryValueCallBacks);
1988   if (! attributes)
1989     goto err;
1991   tmp = AREF (spec, FONT_FAMILY_INDEX);
1992   if (SYMBOLP (tmp) && ! NILP (tmp))
1993     {
1994       CFStringRef family = macfont_create_family_with_symbol (tmp);
1996       if (! family)
1997         goto err;
1998       CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
1999                             family);
2000       CFRelease (family);
2001     }
2003   traits = CFDictionaryCreateMutable (NULL, 4,
2004                                       &kCFTypeDictionaryKeyCallBacks,
2005                                       &kCFTypeDictionaryValueCallBacks);
2006   if (! traits)
2007     goto err;
2009   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
2010     {
2011       tmp = AREF (spec, numeric_traits[i].index);
2012       if (INTEGERP (tmp))
2013         {
2014           CGPoint *point = numeric_traits[i].points;
2015           CGFloat floatval = (XINT (tmp) >> 8); // XXX
2016           CFNumberRef num;
2018           while (point->y < floatval)
2019             point++;
2020           if (point == numeric_traits[i].points)
2021             point++;
2022           else if (point->y == CGFLOAT_MAX)
2023             point--;
2024           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
2025                                        * ((point->x - (point - 1)->x)
2026                                           / (point->y - (point - 1)->y)));
2027           if (floatval > 1.0)
2028             floatval = 1.0;
2029           else if (floatval < -1.0)
2030             floatval = -1.0;
2031           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2032           if (! num)
2033             goto err;
2034           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2035           CFRelease (num);
2036         }
2037     }
2038   if (CFDictionaryGetCount (traits))
2039     CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2041   if (charset)
2042     CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2043                           charset);
2044   if (charset_string)
2045     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2046                           charset_string);
2047   if (langarray)
2048     CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2050   goto finish;
2052  err:
2053   if (attributes)
2054     {
2055       CFRelease (attributes);
2056       attributes = NULL;
2057     }
2059  finish:
2060   if (langarray) CFRelease (langarray);
2061   if (charset && cf_charset_idx < 0) CFRelease (charset);
2062   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2063   if (traits) CFRelease (traits);
2064   if (otspec)
2065     {
2066       if (otspec->nfeatures[0] > 0)
2067         free (otspec->features[0]);
2068       if (otspec->nfeatures[1] > 0)
2069         free (otspec->features[1]);
2070       free (otspec);
2071     }
2073   return attributes;
2076 static Boolean
2077 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2078                                           CFCharacterSetRef charset,
2079                                           Lisp_Object chars,
2080                                           CFArrayRef languages)
2082   Boolean result = true;
2084   if (charset || VECTORP (chars))
2085     {
2086       CFCharacterSetRef desc_charset =
2087         CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2089       if (desc_charset == NULL)
2090         result = false;
2091       else
2092         {
2093           if (charset)
2094             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2095           else                  /* VECTORP (chars) */
2096             {
2097               ptrdiff_t j;
2099               for (j = 0; j < ASIZE (chars); j++)
2100                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2101                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2102                                                             XFASTINT (AREF (chars, j))))
2103                   break;
2104               if (j == ASIZE (chars))
2105                 result = false;
2106             }
2107           CFRelease (desc_charset);
2108         }
2109     }
2110   if (result && languages)
2111     result = mac_font_descriptor_supports_languages (desc, languages);
2113   return result;
2116 static int
2117 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2118                          CTFontSymbolicTraits sym_traits2)
2120   CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2121   int distance = 0;
2123   /* We prefer synthetic bold of italic to synthetic italic of bold
2124      when both bold and italic are available but bold-italic is not
2125      available.  */
2126   if (diff & kCTFontTraitBold)
2127     distance |= (1 << 0);
2128   if (diff & kCTFontTraitItalic)
2129     distance |= (1 << 1);
2130   if (diff & kCTFontTraitMonoSpace)
2131     distance |= (1 << 2);
2133   return distance;
2136 static Boolean
2137 macfont_closest_traits_index_p (CFArrayRef traits_array,
2138                                 CTFontSymbolicTraits target,
2139                                 CFIndex index)
2141   CFIndex i, count = CFArrayGetCount (traits_array);
2142   CTFontSymbolicTraits traits;
2143   int my_distance;
2145   traits = ((CTFontSymbolicTraits) (uintptr_t)
2146             CFArrayGetValueAtIndex (traits_array, index));
2147   my_distance = macfont_traits_distance (target, traits);
2149   for (i = 0; i < count; i++)
2150     if (i != index)
2151       {
2152         traits = ((CTFontSymbolicTraits) (uintptr_t)
2153                   CFArrayGetValueAtIndex (traits_array, i));
2154         if (macfont_traits_distance (target, traits) < my_distance)
2155           return false;
2156       }
2158   return true;
2161 static Lisp_Object
2162 macfont_list (struct frame *f, Lisp_Object spec)
2164   Lisp_Object val = Qnil, family, extra;
2165   int i, n;
2166   CFStringRef family_name = NULL;
2167   CFMutableDictionaryRef attributes = NULL, traits;
2168   Lisp_Object chars = Qnil;
2169   int spacing = -1;
2170   CTFontSymbolicTraits synth_sym_traits = 0;
2171   CFArrayRef families;
2172   CFIndex families_count;
2173   CFCharacterSetRef charset = NULL;
2174   CFArrayRef languages = NULL;
2176   block_input ();
2178   family = AREF (spec, FONT_FAMILY_INDEX);
2179   if (! NILP (family))
2180     {
2181       family_name = macfont_create_family_with_symbol (family);
2182       if (family_name == NULL)
2183         goto finish;
2184     }
2186   attributes = macfont_create_attributes_with_spec (spec);
2187   if (! attributes)
2188     goto finish;
2190   languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2192   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2193     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2195   traits = ((CFMutableDictionaryRef)
2196             CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2198   n = FONT_SLANT_NUMERIC (spec);
2199   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2200     {
2201       synth_sym_traits |= kCTFontTraitItalic;
2202       if (traits)
2203         CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2204     }
2206   n = FONT_WEIGHT_NUMERIC (spec);
2207   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2208     {
2209       synth_sym_traits |= kCTFontTraitBold;
2210       if (traits)
2211         CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2212     }
2214   if (languages
2215       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2216     {
2217       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2219       if (CFStringHasPrefix (language, CFSTR ("ja"))
2220           || CFStringHasPrefix (language, CFSTR ("ko"))
2221           || CFStringHasPrefix (language, CFSTR ("zh")))
2222         synth_sym_traits |= kCTFontTraitMonoSpace;
2223     }
2225   /* Create array of families.  */
2226   if (family_name)
2227     families = CFArrayCreate (NULL, (const void **) &family_name,
2228                               1, &kCFTypeArrayCallBacks);
2229   else
2230     {
2231       CFStringRef pref_family;
2232       CFIndex families_count, pref_family_index = -1;
2234       families = macfont_copy_available_families_cache ();
2235       if (families == NULL)
2236         goto err;
2238       families_count = CFArrayGetCount (families);
2240       /* Move preferred family to the front if exists.  */
2241       pref_family =
2242         mac_font_create_preferred_family_for_attributes (attributes);
2243       if (pref_family)
2244         {
2245           pref_family_index =
2246             CFArrayGetFirstIndexOfValue (families,
2247                                          CFRangeMake (0, families_count),
2248                                          pref_family);
2249           CFRelease (pref_family);
2250         }
2251       if (pref_family_index > 0)
2252         {
2253           CFMutableArrayRef mutable_families =
2254             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2256           if (mutable_families)
2257             {
2258               CFArrayAppendValue (mutable_families,
2259                                   CFArrayGetValueAtIndex (families,
2260                                                           pref_family_index));
2261               CFArrayAppendArray (mutable_families, families,
2262                                   CFRangeMake (0, pref_family_index));
2263               if (pref_family_index + 1 < families_count)
2264                 CFArrayAppendArray (mutable_families, families,
2265                                     CFRangeMake (pref_family_index + 1,
2266                                                  families_count
2267                                                  - (pref_family_index + 1)));
2268               CFRelease (families);
2269               families = mutable_families;
2270             }
2271         }
2272     }
2274   charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2275   if (charset)
2276     {
2277       CFRetain (charset);
2278       CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2279     }
2280   else
2281     {
2282       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2283       if (! NILP (val))
2284         {
2285           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2286           if (CONSP (val) && VECTORP (XCDR (val)))
2287             chars = XCDR (val);
2288         }
2289       val = Qnil;
2290     }
2292   if (languages)
2293     {
2294       CFRetain (languages);
2295       CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2296     }
2298   val = Qnil;
2299   extra = AREF (spec, FONT_EXTRA_INDEX);
2300   families_count = CFArrayGetCount (families);
2301   for (i = 0; i < families_count; i++)
2302     {
2303       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2304       CTFontDescriptorRef pat_desc;
2305       CFArrayRef descs;
2306       CFIndex descs_count;
2307       CFMutableArrayRef filtered_descs, traits_array;
2308       Lisp_Object entity;
2309       int j;
2311       CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2312                             family_name);
2313       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2314       if (! pat_desc)
2315         goto err;
2317       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2318          10.7 returns NULL if pat_desc represents the LastResort font.
2319          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2320          trailing "s") for such a font.  */
2321       if (!CFEqual (family_name, CFSTR ("LastResort")))
2322         descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2323       else
2324         {
2325           CTFontDescriptorRef lr_desc =
2326             CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2327           if (lr_desc)
2328             {
2329               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2330                                      &kCFTypeArrayCallBacks);
2331               CFRelease (lr_desc);
2332             }
2333           else
2334             descs = NULL;
2335         }
2336       CFRelease (pat_desc);
2337       if (! descs)
2338         continue;
2340       descs_count = CFArrayGetCount (descs);
2341       if (descs_count == 0
2342           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2343                                                         charset, chars,
2344                                                         languages))
2345         {
2346           CFRelease (descs);
2347           continue;
2348         }
2350       filtered_descs =
2351         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2352       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2353       for (j = 0; j < descs_count; j++)
2354         {
2355           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2356           CFDictionaryRef dict;
2357           CFNumberRef num;
2358           CTFontSymbolicTraits sym_traits;
2360           dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2361           if (dict == NULL)
2362             continue;
2364           num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2365           CFRelease (dict);
2366           if (num == NULL
2367               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2368             continue;
2370           if (spacing >= 0
2371               && !(synth_sym_traits & kCTFontTraitMonoSpace)
2372               && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2373                   != (spacing >= FONT_SPACING_MONO)))
2374             continue;
2376           /* Don't use a color bitmap font until it is supported on
2377              free platforms.  */
2378           if (sym_traits & kCTFontTraitColorGlyphs)
2379             continue;
2381           if (j > 0
2382               && !macfont_supports_charset_and_languages_p (desc, charset,
2383                                                             chars, languages))
2384             continue;
2386           CFArrayAppendValue (filtered_descs, desc);
2387           CFArrayAppendValue (traits_array,
2388                               (const void *) (uintptr_t) sym_traits);
2389         }
2391       CFRelease (descs);
2392       descs = filtered_descs;
2393       descs_count = CFArrayGetCount (descs);
2395       for (j = 0; j < descs_count; j++)
2396         {
2397           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2398           CTFontSymbolicTraits sym_traits =
2399             ((CTFontSymbolicTraits) (uintptr_t)
2400              CFArrayGetValueAtIndex (traits_array, j));
2401           CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2403           mask_min = ((synth_sym_traits ^ sym_traits)
2404                       & (kCTFontTraitItalic | kCTFontTraitBold));
2405           if (FONT_SLANT_NUMERIC (spec) < 0)
2406             mask_min &= ~kCTFontTraitItalic;
2407           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2408             mask_min &= ~kCTFontTraitBold;
2410           mask_max = (synth_sym_traits & ~sym_traits);
2411           /* Synthetic bold does not work for bitmap-only fonts on Mac
2412              OS X 10.6.  */
2413           if ((mask_min ^ mask_max) & kCTFontTraitBold)
2414             {
2415               CFNumberRef format =
2416                 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2418               if (format)
2419                 {
2420                   uint32_t format_val;
2422                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2423                                         &format_val)
2424                       && format_val == kCTFontFormatBitmap)
2425                     mask_max &= ~kCTFontTraitBold;
2426                 }
2427             }
2428           if (spacing >= 0)
2429             mask_min |= (mask_max & kCTFontTraitMonoSpace);
2431           for (mmask = (mask_min & kCTFontTraitMonoSpace);
2432                mmask <= (mask_max & kCTFontTraitMonoSpace);
2433                mmask += kCTFontTraitMonoSpace)
2434             for (bmask = (mask_min & kCTFontTraitBold);
2435                  bmask <= (mask_max & kCTFontTraitBold);
2436                  bmask += kCTFontTraitBold)
2437               for (imask = (mask_min & kCTFontTraitItalic);
2438                    imask <= (mask_max & kCTFontTraitItalic);
2439                    imask += kCTFontTraitItalic)
2440                 {
2441                   CTFontSymbolicTraits synth = (imask | bmask | mmask);
2443                   if (synth == 0
2444                       || macfont_closest_traits_index_p (traits_array,
2445                                                          (sym_traits | synth),
2446                                                          j))
2447                     {
2448                       entity = macfont_descriptor_entity (desc, extra, synth);
2449                       if (! NILP (entity))
2450                         val = Fcons (entity, val);
2451                     }
2452                 }
2453         }
2455       CFRelease (traits_array);
2456       CFRelease (descs);
2457     }
2459   CFRelease (families);
2460   val = Fnreverse (val);
2461   goto finish;
2462  err:
2463   val = Qnil;
2465  finish:
2466   FONT_ADD_LOG ("macfont-list", spec, val);
2467   if (charset) CFRelease (charset);
2468   if (languages) CFRelease (languages);
2469   if (attributes) CFRelease (attributes);
2470   if (family_name) CFRelease (family_name);
2472   unblock_input ();
2474   return val;
2477 static Lisp_Object
2478 macfont_match (struct frame * frame, Lisp_Object spec)
2480   Lisp_Object entity = Qnil;
2481   CFMutableDictionaryRef attributes;
2482   CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2484   block_input ();
2486   attributes = macfont_create_attributes_with_spec (spec);
2487   if (attributes)
2488     {
2489       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2490       CFRelease (attributes);
2491     }
2492   if (pat_desc)
2493     {
2494       desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2495       CFRelease (pat_desc);
2496     }
2497   if (desc)
2498     {
2499       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2500                                           0);
2501       CFRelease (desc);
2502     }
2503   unblock_input ();
2505   FONT_ADD_LOG ("macfont-match", spec, entity);
2506   return entity;
2509 static Lisp_Object
2510 macfont_list_family (struct frame *frame)
2512   Lisp_Object list = Qnil;
2513   CFArrayRef families;
2515   block_input ();
2517   families = macfont_copy_available_families_cache ();
2518   if (families)
2519     {
2520       CFIndex i, count = CFArrayGetCount (families);
2522       for (i = 0; i < count; i++)
2523         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2524       CFRelease (families);
2525     }
2527   unblock_input ();
2529   return list;
2532 static void
2533 macfont_free_entity (Lisp_Object entity)
2535   Lisp_Object val = assq_no_quit (QCfont_entity,
2536                                   AREF (entity, FONT_EXTRA_INDEX));
2537   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2539   block_input ();
2540   CFRelease (name);
2541   unblock_input ();
2544 static Lisp_Object
2545 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2547   Lisp_Object val, font_object;
2548   CFStringRef font_name;
2549   struct macfont_info *macfont_info = NULL;
2550   struct font *font;
2551   int size;
2552   CTFontRef macfont;
2553   CTFontSymbolicTraits sym_traits;
2554   char name[256];
2555   int len, i, total_width;
2556   CGGlyph glyph;
2557   CGFloat ascent, descent, leading;
2559   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2560   if (! CONSP (val)
2561       || XTYPE (XCDR (val)) != Lisp_Misc
2562       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2563     return Qnil;
2564   font_name = XSAVE_POINTER (XCDR (val), 0);
2565   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2567   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2568   if (size == 0)
2569     size = pixel_size;
2571   block_input ();
2572   macfont = CTFontCreateWithName (font_name, size, NULL);
2573   if (macfont)
2574     {
2575       int fontsize = (int) [((NSFont *) macfont) pointSize];
2576       if (fontsize != size) size = fontsize;
2577     }
2578   unblock_input ();
2579   if (! macfont)
2580     return Qnil;
2582   font_object = font_build_object (VECSIZE (struct macfont_info),
2583                                    Qmac_ct, entity, size);
2584   font = XFONT_OBJECT (font_object);
2585   font->pixel_size = size;
2586   font->driver = &macfont_driver;
2587   font->encoding_charset = font->repertory_charset = -1;
2589   block_input ();
2591   macfont_info = (struct macfont_info *) font;
2592   macfont_info->macfont = macfont;
2593   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2595   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2596   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2597     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2598                                                                   size);
2599   else
2600     macfont_info->screen_font = NULL;
2601   macfont_info->cache = macfont_lookup_cache (font_name);
2602   macfont_retain_cache (macfont_info->cache);
2603   macfont_info->metrics = NULL;
2604   macfont_info->metrics_nrows = 0;
2605   macfont_info->synthetic_italic_p = 0;
2606   macfont_info->synthetic_bold_p = 0;
2607   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2608   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2609   if (!(sym_traits & kCTFontTraitItalic)
2610       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2611     macfont_info->synthetic_italic_p = 1;
2612   if (!(sym_traits & kCTFontTraitBold)
2613       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2614     macfont_info->synthetic_bold_p = 1;
2615   if (sym_traits & kCTFontTraitMonoSpace)
2616     macfont_info->spacing = MACFONT_SPACING_MONO;
2617   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2618            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2619                == FONT_SPACING_SYNTHETIC_MONO))
2620     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2621   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2622     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2623   else
2624     {
2625       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2626       if (CONSP (val))
2627         macfont_info->antialias =
2628           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2629     }
2630   macfont_info->color_bitmap_p = 0;
2631   if (sym_traits & kCTFontTraitColorGlyphs)
2632     macfont_info->color_bitmap_p = 1;
2634   glyph = macfont_get_glyph_for_character (font, ' ');
2635   if (glyph != kCGFontIndexInvalid)
2636     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2637   else
2638     /* dirty workaround */
2639     font->space_width = pixel_size;
2641   total_width = font->space_width;
2642   for (i = 1; i < 95; i++)
2643     {
2644       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2645       if (glyph == kCGFontIndexInvalid)
2646         break;
2647       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2648     }
2649   if (i == 95)
2650     font->average_width = total_width / 95;
2651   else
2652     font->average_width = font->space_width; /* XXX */
2654   if (!(macfont_info->screen_font
2655         && mac_screen_font_get_metrics (macfont_info->screen_font,
2656                                         &ascent, &descent, &leading)))
2657     {
2658       CFStringRef family_name;
2660       ascent = CTFontGetAscent (macfont);
2661       descent = CTFontGetDescent (macfont);
2662       leading = CTFontGetLeading (macfont);
2663       /* AppKit and WebKit do some adjustment to the heights of
2664          Courier, Helvetica, and Times.  */
2665       family_name = CTFontCopyFamilyName (macfont);
2666       if (family_name)
2667         {
2668           if (CFEqual (family_name, CFSTR ("Courier"))
2669               || CFEqual (family_name, CFSTR ("Helvetica"))
2670               || CFEqual (family_name, CFSTR ("Times")))
2671             ascent += (ascent + descent) * .15f;
2672           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2673             {
2674               leading *= .25f;
2675               ascent += leading;
2676             }
2677           CFRelease (family_name);
2678         }
2679     }
2680   font->ascent = ascent + 0.5f;
2681   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2682   if (CONSP (val) && !NILP (XCDR (val)))
2683     font->descent = descent + 0.5f;
2684   else
2685     font->descent = descent + leading + 0.5f;
2686   font->height = font->ascent + font->descent;
2688   font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2689   font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2691   unblock_input ();
2693   /* Unfortunately Xft doesn't provide a way to get minimum char
2694      width.  So, we use space_width instead.  */
2695   font->min_width = font->max_width = font->space_width; /* XXX */
2697   font->baseline_offset = 0;
2698   font->relative_compose = 0;
2699   font->default_ascent = 0;
2700   font->vertical_centering = 0;
2702   return font_object;
2705 static void
2706 macfont_close (struct font *font)
2708   struct macfont_info *macfont_info = (struct macfont_info *) font;
2710   if (macfont_info->cache)
2711     {
2712       int i;
2714       block_input ();
2715       CFRelease (macfont_info->macfont);
2716       CGFontRelease (macfont_info->cgfont);
2717       if (macfont_info->screen_font)
2718         CFRelease (macfont_info->screen_font);
2719       macfont_release_cache (macfont_info->cache);
2720       for (i = 0; i < macfont_info->metrics_nrows; i++)
2721         if (macfont_info->metrics[i])
2722           xfree (macfont_info->metrics[i]);
2723       if (macfont_info->metrics)
2724         xfree (macfont_info->metrics);
2725       macfont_info->cache = NULL;
2726       unblock_input ();
2727     }
2730 static int
2731 macfont_has_char (Lisp_Object font, int c)
2733   int result;
2734   CFCharacterSetRef charset;
2736   block_input ();
2737   if (FONT_ENTITY_P (font))
2738     {
2739       Lisp_Object val;
2740       CFStringRef name;
2742       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2743       val = XCDR (val);
2744       name = XSAVE_POINTER (val, 0);
2745       charset = macfont_get_cf_charset_for_name (name);
2746     }
2747   else
2748     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2750   result = CFCharacterSetIsLongCharacterMember (charset, c);
2751   unblock_input ();
2753   return result;
2756 static unsigned
2757 macfont_encode_char (struct font *font, int c)
2759   CGGlyph glyph;
2761   block_input ();
2762   glyph = macfont_get_glyph_for_character (font, c);
2763   unblock_input ();
2765   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2768 static void
2769 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2770                       struct font_metrics *metrics)
2772   int width, i;
2774   block_input ();
2775   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2776   for (i = 1; i < nglyphs; i++)
2777     {
2778       struct font_metrics m;
2779       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2780                                      NULL, 0);
2782       if (metrics)
2783         {
2784           if (width + m.lbearing < metrics->lbearing)
2785             metrics->lbearing = width + m.lbearing;
2786           if (width + m.rbearing > metrics->rbearing)
2787             metrics->rbearing = width + m.rbearing;
2788           if (m.ascent > metrics->ascent)
2789             metrics->ascent = m.ascent;
2790           if (m.descent > metrics->descent)
2791             metrics->descent = m.descent;
2792         }
2793       width += w;
2794     }
2795   unblock_input ();
2797   if (metrics)
2798     metrics->width = width;
2801 static int
2802 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2803               bool with_background)
2805   struct frame * f = s->f;
2806   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2807   CGRect background_rect;
2808   CGPoint text_position;
2809   CGGlyph *glyphs;
2810   CGPoint *positions;
2811   CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2812   bool no_antialias_p =
2813     (NILP (ns_antialias_text)
2814      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2815      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2816          && font_size <= macfont_antialias_threshold));
2817   int len = to - from;
2818   struct face *face = s->face;
2819   CGContextRef context;
2821   block_input ();
2823   if (with_background)
2824     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2825                                   s->width, FONT_HEIGHT (s->font));
2826   else
2827     background_rect = CGRectNull;
2829   text_position = CGPointMake (x, -y);
2830   glyphs = xmalloc (sizeof (CGGlyph) * len);
2831   {
2832     CGFloat advance_delta = 0;
2833     int i;
2834     CGFloat total_width = 0;
2836     positions = xmalloc (sizeof (CGPoint) * len);
2837     for (i = 0; i < len; i++)
2838       {
2839         int width;
2841         glyphs[i] = s->char2b[from + i];
2842         width = (s->padding_p ? 1
2843                  : macfont_glyph_extents (s->font, glyphs[i],
2844                                           NULL, &advance_delta,
2845                                           no_antialias_p));
2846         positions[i].x = total_width + advance_delta;
2847         positions[i].y = 0;
2848         total_width += width;
2849       }
2850   }
2852   context = [[NSGraphicsContext currentContext] graphicsPort];
2853   CGContextSaveGState (context);
2855   if (!CGRectIsNull (background_rect))
2856     {
2857       if (s->hl == DRAW_MOUSE_FACE)
2858         {
2859           face = FACE_FROM_ID_OR_NULL (s->f,
2860                                        MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2861           if (!face)
2862             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2863         }
2864       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2865       CGContextFillRects (context, &background_rect, 1);
2866     }
2868   if (macfont_info->cgfont)
2869     {
2870       CGAffineTransform atfm;
2872       CGContextScaleCTM (context, 1, -1);
2873       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2874       if (macfont_info->synthetic_italic_p)
2875         atfm = synthetic_italic_atfm;
2876       else
2877         atfm = CGAffineTransformIdentity;
2878       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2879         {
2880           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2881           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2882           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2883         }
2884       if (no_antialias_p)
2885         CGContextSetShouldAntialias (context, false);
2887       CGContextSetTextMatrix (context, atfm);
2888       CGContextSetTextPosition (context, text_position.x, text_position.y);
2890 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2891       if (macfont_info->color_bitmap_p
2892 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2893           && CTFontDrawGlyphs != NULL
2894 #endif
2895           )
2896         {
2897           if (len > 0)
2898             {
2899               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2900                                 context);
2901             }
2902         }
2903       else
2904 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2905         {
2906           CGContextSetFont (context, macfont_info->cgfont);
2907           CGContextSetFontSize (context, font_size);
2908           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2909         }
2910     }
2913   xfree (glyphs);
2914   xfree (positions);
2915   CGContextRestoreGState (context);
2917   unblock_input ();
2919   return len;
2922 static Lisp_Object
2923 macfont_shape (Lisp_Object lgstring)
2925   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2926   struct macfont_info *macfont_info = (struct macfont_info *) font;
2927   CTFontRef macfont = macfont_info->macfont;
2928   ptrdiff_t glyph_len, len, i, j;
2929   CFIndex nonbmp_len;
2930   UniChar *unichars;
2931   CFIndex *nonbmp_indices;
2932   CFStringRef string;
2933   CFIndex used = 0;
2934   struct mac_glyph_layout *glyph_layouts;
2936   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2937   nonbmp_len = 0;
2938   for (i = 0; i < glyph_len; i++)
2939     {
2940       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2942       if (NILP (lglyph))
2943         break;
2944       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2945         nonbmp_len++;
2946     }
2948   len = i;
2950   if (INT_MAX / 2 < len)
2951     memory_full (SIZE_MAX);
2953   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2954   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2955   for (i = j = 0; i < len; i++)
2956     {
2957       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2959       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2960         {
2961           nonbmp_indices[j] = i + j;
2962           j++;
2963         }
2964     }
2965   nonbmp_indices[j] = len + j;  /* sentinel */
2967   block_input ();
2969   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2970                                                kCFAllocatorNull);
2971   if (string)
2972     {
2973       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2974       if (macfont_info->screen_font)
2975         used = mac_screen_font_shape (macfont_info->screen_font, string,
2976                                       glyph_layouts, glyph_len);
2977       else
2978         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2979       CFRelease (string);
2980     }
2982   unblock_input ();
2984   if (used == 0)
2985     return Qnil;
2987   block_input ();
2989   for (i = 0; i < used; i++)
2990     {
2991       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2992       struct mac_glyph_layout *gl = glyph_layouts + i;
2993       EMACS_INT from, to;
2994       struct font_metrics metrics;
2995       int xoff, yoff, wadjust;
2997       if (NILP (lglyph))
2998         {
2999           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
3000           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
3001         }
3003       from = gl->comp_range.location;
3004       /* Convert UTF-16 index to UTF-32.  */
3005       j = 0;
3006       while (nonbmp_indices[j] < from)
3007         j++;
3008       from -= j;
3009       LGLYPH_SET_FROM (lglyph, from);
3011       to = gl->comp_range.location + gl->comp_range.length;
3012       /* Convert UTF-16 index to UTF-32.  */
3013       while (nonbmp_indices[j] < to)
3014         j++;
3015       to -= j;
3016       LGLYPH_SET_TO (lglyph, to - 1);
3018       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3019          the composition is trivial.  */
3020       {
3021         UTF32Char c;
3023         if (unichars[gl->string_index] >= 0xD800
3024             && unichars[gl->string_index] < 0xDC00)
3025           c = (((unichars[gl->string_index] - 0xD800) << 10)
3026                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3027         else
3028           c = unichars[gl->string_index];
3029         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3030           c = 0;
3031         LGLYPH_SET_CHAR (lglyph, c);
3032       }
3034       {
3035         unsigned long cc = gl->glyph_id;
3036         LGLYPH_SET_CODE (lglyph, cc);
3037       }
3039       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3040       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3041       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3042       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3043       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3044       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3046       xoff = lround (gl->advance_delta);
3047       yoff = lround (- gl->baseline_delta);
3048       wadjust = lround (gl->advance);
3049       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3050         {
3051           Lisp_Object vec;
3053           vec = Fmake_vector (make_number (3), Qnil);
3054           ASET (vec, 0, make_number (xoff));
3055           ASET (vec, 1, make_number (yoff));
3056           ASET (vec, 2, make_number (wadjust));
3057           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3058         }
3059     }
3061   unblock_input ();
3063   return make_number (used);
3066 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3067 typedef UInt8 UINT24[3];
3069 #pragma pack(push, 1)
3070 struct variation_selector_record
3072   UINT24 var_selector;
3073   UInt32 default_uvs_offset, non_default_uvs_offset;
3075 struct uvs_table
3077   UInt16 format;
3078   UInt32 length, num_var_selector_records;
3079   struct variation_selector_record variation_selector_records[1];
3081 #define SIZEOF_UVS_TABLE_HEADER                                         \
3082   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3084 struct unicode_value_range
3086   UINT24 start_unicode_value;
3087   UInt8 additional_count;
3089 struct default_uvs_table {
3090   UInt32 num_unicode_value_ranges;
3091   struct unicode_value_range unicode_value_ranges[1];
3093 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3094   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3096 struct uvs_mapping
3098   UINT24 unicode_value;
3099   UInt16 glyph_id;
3101 struct non_default_uvs_table
3103   UInt32 num_uvs_mappings;
3104   struct uvs_mapping uvs_mappings[1];
3106 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3107   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3108 #pragma pack(pop)
3110 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3111 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3112    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3113    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3114 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3115 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3116 /* Succeeding one byte should also be accessible.  */
3117 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3118 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3120 /* Return UVS subtable for the specified FONT.  If the subtable is not
3121    found or ill-formatted, then return NULL.  */
3123 static CFDataRef
3124 mac_font_copy_uvs_table (CTFontRef font)
3126   CFDataRef cmap_table, uvs_table = NULL;
3128   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3129                                 kCTFontTableOptionNoOptions);
3130   if (cmap_table)
3131     {
3132       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3133       struct uvs_table *uvs;
3134       struct variation_selector_record *records;
3135       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3137 #if __LP64__
3138       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3139         goto finish;
3140 #endif
3142       cmap_len = CFDataGetLength (cmap_table);
3143       if (sizeof_sfntCMapHeader > cmap_len)
3144         goto finish;
3146       ntables = BUINT16_VALUE (cmap->numTables);
3147       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3148                      / sizeof_sfntCMapEncoding))
3149         goto finish;
3151       for (i = 0; i < ntables; i++)
3152         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3153              == kFontUnicodePlatform)
3154             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3155                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3156           {
3157             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3158             break;
3159           }
3160       if (i == ntables
3161           || uvs_offset > cmap_len
3162           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3163         goto finish;
3165       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3166       uvs_len = BUINT32_VALUE (uvs->length);
3167       if (uvs_len > cmap_len - uvs_offset
3168           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3169         goto finish;
3171       if (BUINT16_VALUE (uvs->format) != 14)
3172         goto finish;
3174       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3175       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3176                       / sizeof (struct variation_selector_record)))
3177         goto finish;
3179       records = uvs->variation_selector_records;
3180       for (i = 0; i < nrecords; i++)
3181         {
3182           UInt32 default_uvs_offset, non_default_uvs_offset;
3184           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3185           if (default_uvs_offset)
3186             {
3187               struct default_uvs_table *default_uvs;
3188               UInt32 nranges;
3190               if (default_uvs_offset > uvs_len
3191                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3192                       > uvs_len - default_uvs_offset))
3193                 goto finish;
3195               default_uvs = ((struct default_uvs_table *)
3196                              ((UInt8 *) uvs + default_uvs_offset));
3197               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3198               if (nranges > ((uvs_len - default_uvs_offset
3199                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3200                              / sizeof (struct unicode_value_range)))
3201                 goto finish;
3202               /* Now 2 * nranges can't overflow, so we can safely use
3203                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3204                  mac_font_get_glyphs_for_variants.  */
3205             }
3207           non_default_uvs_offset =
3208             BUINT32_VALUE (records[i].non_default_uvs_offset);
3209           if (non_default_uvs_offset)
3210             {
3211               struct non_default_uvs_table *non_default_uvs;
3212               UInt32 nmappings;
3214               if (non_default_uvs_offset > uvs_len
3215                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3216                       > uvs_len - non_default_uvs_offset))
3217                 goto finish;
3219               non_default_uvs = ((struct non_default_uvs_table *)
3220                                  ((UInt8 *) uvs + non_default_uvs_offset));
3221               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3222               if (nmappings > ((uvs_len - non_default_uvs_offset
3223                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3224                                / sizeof (struct uvs_mapping)))
3225                 goto finish;
3226               /* Now 2 * nmappings can't overflow, so we can safely
3227                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3228                  in mac_font_get_glyphs_for_variants.  */
3229             }
3230         }
3232       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3234     finish:
3235       CFRelease (cmap_table);
3236     }
3238   return uvs_table;
3241 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3242    sequence consisting of the given base character C and each
3243    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3244    result (explained below) into the corresponding GLYPHS[i].  If the
3245    entry is found in the Default UVS Table, then the result is 0.  If
3246    the entry is found in the Non-Default UVS Table, then the result is
3247    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3248    elements in SELECTORS must be sorted in strictly increasing
3249    order.  */
3251 static void
3252 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3253                                   const UTF32Char selectors[], CGGlyph glyphs[],
3254                                   CFIndex count)
3256   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3257   struct variation_selector_record *records = uvs->variation_selector_records;
3258   CFIndex i;
3259   UInt32 ir, nrecords;
3260   dispatch_queue_t queue =
3261     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3262   dispatch_group_t group = dispatch_group_create ();
3264   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3265   i = 0;
3266   ir = 0;
3267   while (i < count && ir < nrecords)
3268     {
3269       UInt32 default_uvs_offset, non_default_uvs_offset;
3271       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3272         {
3273           glyphs[i++] = kCGFontIndexInvalid;
3274           continue;
3275         }
3276       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3277         {
3278           ir++;
3279           continue;
3280         }
3282       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3283       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3284       non_default_uvs_offset =
3285         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3286       dispatch_group_async (group, queue, ^{
3287           glyphs[i] = kCGFontIndexInvalid;
3289           if (default_uvs_offset)
3290             {
3291               struct default_uvs_table *default_uvs =
3292                 (struct default_uvs_table *) ((UInt8 *) uvs
3293                                               + default_uvs_offset);
3294               struct unicode_value_range *ranges =
3295                 default_uvs->unicode_value_ranges;
3296               UInt32 lo, hi;
3298               lo = 0;
3299               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3300               while (lo < hi)
3301                 {
3302                   UInt32 mid = (lo + hi) / 2;
3304                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3305                     hi = mid;
3306                   else
3307                     lo = mid + 1;
3308                 }
3309               if (hi > 0
3310                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3311                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3312                 glyphs[i] = 0;
3313             }
3315           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3316             {
3317               struct non_default_uvs_table *non_default_uvs =
3318                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3319                                                   + non_default_uvs_offset);
3320               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3321               UInt32 lo, hi;
3323               lo = 0;
3324               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3325               while (lo < hi)
3326                 {
3327                   UInt32 mid = (lo + hi) / 2;
3329                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3330                     hi = mid;
3331                   else
3332                     lo = mid + 1;
3333                 }
3334               if (hi > 0 &&
3335                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3336                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3337             }
3338         });
3339       i++;
3340       ir++;
3341     }
3342   while (i < count)
3343     glyphs[i++] = kCGFontIndexInvalid;
3344   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3345   dispatch_release (group);
3348 static int
3349 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3351   CFDataRef uvs_table;
3352   CTCharacterCollection uvs_collection;
3353   int i, n = 0;
3355   block_input ();
3356   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3358   if (uvs_table)
3359     {
3360       UTF32Char selectors[256];
3361       CGGlyph glyphs[256];
3363       for (i = 0; i < 16; i++)
3364         selectors[i] = 0xFE00 + i;
3365       for (; i < 256; i++)
3366         selectors[i] = 0xE0100 + (i - 16);
3367       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3368       for (i = 0; i < 256; i++)
3369         {
3370           CGGlyph glyph = glyphs[i];
3372           if (uvs_collection != kCTCharacterCollectionIdentityMapping
3373               && glyph != kCGFontIndexInvalid)
3374             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3375           if (glyph == kCGFontIndexInvalid)
3376             variations[i] = 0;
3377           else
3378             {
3379               variations[i] = (glyph ? glyph
3380                                : macfont_get_glyph_for_character (font, c));
3381               n++;
3382             }
3383         }
3384     }
3385   unblock_input ();
3387   return n;
3390 static const char *const macfont_booleans[] = {
3391   ":antialias",
3392   ":minspace",
3393   NULL,
3396 static const char *const macfont_non_booleans[] = {
3397   ":lang",
3398   ":script",
3399   ":destination",
3400   NULL,
3403 static void
3404 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3406   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3409 static Boolean
3410 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3411                                         CFArrayRef languages)
3413   Boolean result = true;
3414   CFArrayRef desc_languages =
3415     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3417   if (desc_languages == NULL)
3418     result = false;
3419   else
3420     {
3421       CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3422       CFIndex i, languages_count = CFArrayGetCount (languages);
3424       for (i = 0; i < languages_count; i++)
3425         {
3426           CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3428           if (!CFArrayContainsValue (desc_languages, range, language)
3429               /* PingFang SC contains "zh" and "zh-Hant" as covered
3430                  languages, but does not contain "zh-Hans".  */
3431               && !(CFEqual (language, CFSTR ("zh-Hans"))
3432                    && CFArrayContainsValue (desc_languages, range,
3433                                             CFSTR ("zh"))))
3434             {
3435               result = false;
3436               break;
3437             }
3438         }
3439       CFRelease (desc_languages);
3440     }
3442   return result;
3445 static CFStringRef
3446 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3448   CFStringRef result = NULL;
3449   CFStringRef charset_string =
3450     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3452   if (charset_string && CFStringGetLength (charset_string) > 0)
3453     {
3454       CFStringRef keys[] = {
3455 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3456         kCTLanguageAttributeName
3457 #else
3458         CFSTR ("NSLanguage")
3459 #endif
3460       };
3461       CFTypeRef values[] = {NULL};
3462       CFIndex num_values = 0;
3463       CFArrayRef languages
3464         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3466       if (languages && CFArrayGetCount (languages) > 0)
3467         {
3468           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3469             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3470           else
3471             {
3472               CFCharacterSetRef charset =
3473                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3475               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3476             }
3477         }
3478       if (result == NULL)
3479         {
3480           CFAttributedStringRef attr_string = NULL;
3481           CTLineRef ctline = NULL;
3482           CFDictionaryRef attrs
3483             = CFDictionaryCreate (NULL, (const void **) keys,
3484                                   (const void **) values, num_values,
3485                                   &kCFTypeDictionaryKeyCallBacks,
3486                                   &kCFTypeDictionaryValueCallBacks);
3488           if (attrs)
3489             {
3490               attr_string = CFAttributedStringCreate (NULL, charset_string,
3491                                                       attrs);
3492               CFRelease (attrs);
3493             }
3494           if (attr_string)
3495             {
3496               ctline = CTLineCreateWithAttributedString (attr_string);
3497               CFRelease (attr_string);
3498             }
3499           if (ctline)
3500             {
3501               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3502               CFIndex i, nruns = CFArrayGetCount (runs);
3503               CTFontRef font;
3505               for (i = 0; i < nruns; i++)
3506                 {
3507                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3508                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3509                   CTFontRef font_in_run;
3511                   if (attributes == NULL)
3512                     break;
3513                   font_in_run =
3514                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3515                   if (font_in_run == NULL)
3516                     break;
3517                   if (i == 0)
3518                     font = font_in_run;
3519                   else if (!mac_font_equal_in_postscript_name (font,
3520                                                                font_in_run))
3521                     break;
3522                 }
3523               if (nruns > 0 && i == nruns)
3524                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3525               CFRelease (ctline);
3526             }
3527         }
3528     }
3530   return result;
3533 static inline double
3534 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3536   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3537                                      &glyph, NULL, 1);
3540 static inline CGRect
3541 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3543   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3544                                           &glyph, NULL, 1);
3547 static CFArrayRef
3548 mac_font_create_available_families (void)
3550   CFMutableArrayRef families = NULL;
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     }
3573   return families;
3576 static Boolean
3577 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3579   Boolean result;
3580   CFStringRef name1, name2;
3582   if (font1 == font2)
3583     return true;
3585   result = false;
3586   name1 = CTFontCopyPostScriptName (font1);
3587   if (name1)
3588     {
3589       name2 = CTFontCopyPostScriptName (font2);
3590       if (name2)
3591         {
3592           result = CFEqual (name1, name2);
3593           CFRelease (name2);
3594         }
3595       CFRelease (name1);
3596     }
3598   return result;
3601 static CTLineRef
3602 mac_font_create_line_with_string_and_font (CFStringRef string,
3603                                            CTFontRef macfont)
3605   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3606   CFTypeRef values[] = {NULL, NULL};
3607   CFDictionaryRef attributes = NULL;
3608   CFAttributedStringRef attr_string = NULL;
3609   CTLineRef ctline = NULL;
3610   float float_zero = 0.0f;
3612   values[0] = macfont;
3613   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3614   if (values[1])
3615     {
3616       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3617                                        (const void **) values,
3618                                        ARRAYELTS (keys),
3619                                        &kCFTypeDictionaryKeyCallBacks,
3620                                        &kCFTypeDictionaryValueCallBacks);
3621       CFRelease (values[1]);
3622     }
3623   if (attributes)
3624     {
3625       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3626       CFRelease (attributes);
3627     }
3628   if (attr_string)
3629     {
3630       ctline = CTLineCreateWithAttributedString (attr_string);
3631       CFRelease (attr_string);
3632     }
3633   if (ctline)
3634     {
3635       /* Abandon if ctline contains some fonts other than the
3636          specified one.  */
3637       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3638       CFIndex i, nruns = CFArrayGetCount (runs);
3640       for (i = 0; i < nruns; i++)
3641         {
3642           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3643           CFDictionaryRef attributes = CTRunGetAttributes (run);
3644           CTFontRef font_in_run;
3646           if (attributes == NULL)
3647             break;
3648           font_in_run =
3649             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3650           if (font_in_run == NULL)
3651             break;
3652           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3653             break;
3654         }
3655       if (i < nruns)
3656         {
3657           CFRelease (ctline);
3658           ctline = NULL;
3659         }
3660     }
3662   return ctline;
3665 static CFIndex
3666 mac_font_shape (CTFontRef font, CFStringRef string,
3667                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3669   CFIndex used, result = 0;
3670   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3672   if (ctline == NULL)
3673     return 0;
3675   used = CTLineGetGlyphCount (ctline);
3676   if (used <= glyph_len)
3677     {
3678       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3679       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3680       CGFloat total_advance = 0;
3681       CFIndex total_glyph_count = 0;
3683       for (k = 0; k < ctrun_count; k++)
3684         {
3685           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3686           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3687           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3688           CFRange string_range, comp_range, range;
3689           CFIndex *permutation;
3691           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3692             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3693           else
3694             permutation = NULL;
3696 #define RIGHT_TO_LEFT_P permutation
3698           /* Now the `comp_range' member of struct mac_glyph_layout is
3699              temporarily used as a work area such that:
3700              glbuf[i].comp_range.location =
3701              min {compRange[i + 1].location, ...,
3702                      compRange[glyph_count - 1].location,
3703                      maxRange (stringRangeForCTRun)}
3704              glbuf[i].comp_range.length = maxRange (compRange[i])
3705              where compRange[i] is the range of composed characters
3706              containing i-th glyph.  */
3707           string_range = CTRunGetStringRange (ctrun);
3708           min_location = string_range.location + string_range.length;
3709           for (i = 0; i < glyph_count; i++)
3710             {
3711               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3712               CFIndex glyph_index;
3713               CFRange rng;
3715               if (!RIGHT_TO_LEFT_P)
3716                 glyph_index = glyph_count - i - 1;
3717               else
3718                 glyph_index = i;
3719               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3720                                      &gl->string_index);
3721               rng =
3722                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3723                                                              gl->string_index);
3724               gl->comp_range.location = min_location;
3725               gl->comp_range.length = rng.location + rng.length;
3726               if (rng.location < min_location)
3727                 min_location = rng.location;
3728             }
3730           /* Fill the `comp_range' member of struct mac_glyph_layout,
3731              and setup a permutation for right-to-left text.  */
3732           comp_range = CFRangeMake (string_range.location, 0);
3733           range = CFRangeMake (0, 0);
3734           while (1)
3735             {
3736               struct mac_glyph_layout *gl =
3737                 glbuf + range.location + range.length;
3739               if (gl->comp_range.length
3740                   > comp_range.location + comp_range.length)
3741                 comp_range.length = gl->comp_range.length - comp_range.location;
3742               min_location = gl->comp_range.location;
3743               range.length++;
3745               if (min_location >= comp_range.location + comp_range.length)
3746                 {
3747                   comp_range.length = min_location - comp_range.location;
3748                   for (i = 0; i < range.length; i++)
3749                     {
3750                       glbuf[range.location + i].comp_range = comp_range;
3751                       if (RIGHT_TO_LEFT_P)
3752                         permutation[range.location + i] =
3753                           range.location + range.length - i - 1;
3754                     }
3756                   comp_range = CFRangeMake (min_location, 0);
3757                   range.location += range.length;
3758                   range.length = 0;
3759                   if (range.location == glyph_count)
3760                     break;
3761                 }
3762             }
3764           /* Then fill the remaining members.  */
3765           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3766                range.location++)
3767             {
3768               struct mac_glyph_layout *gl;
3769               CGPoint position;
3770               CGFloat max_x;
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               max_x = position.x + CTRunGetTypographicBounds (ctrun, range,
3793                                                               NULL, NULL, NULL);
3794               max_x = max (max_x, total_advance);
3795               gl->advance_delta = position.x - total_advance;
3796               gl->baseline_delta = position.y;
3797               gl->advance = max_x - total_advance;
3798               total_advance = max_x;
3799             }
3801           if (RIGHT_TO_LEFT_P)
3802             xfree (permutation);
3804 #undef RIGHT_TO_LEFT_P
3806           total_glyph_count += glyph_count;
3807         }
3809       result = used;
3810     }
3811   CFRelease (ctline);
3813   return result;
3816 /* The function below seems to cause a memory leak for the CFString
3817    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3818    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3819 #if USE_CT_GLYPH_INFO
3820 static CGGlyph
3821 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3822                               CGFontIndex cid)
3824   CGGlyph result = kCGFontIndexInvalid;
3825   UniChar characters[] = {0xfffd};
3826   CFStringRef string;
3827   CFAttributedStringRef attr_string = NULL;
3828   CTLineRef ctline = NULL;
3830   string = CFStringCreateWithCharacters (NULL, characters,
3831                                          ARRAYELTS (characters));
3833   if (string)
3834     {
3835       CTGlyphInfoRef glyph_info =
3836         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3837       CFDictionaryRef attributes = NULL;
3839       if (glyph_info)
3840         {
3841           CFStringRef keys[] = {kCTFontAttributeName,
3842                                 kCTGlyphInfoAttributeName};
3843           CFTypeRef values[] = {font, glyph_info};
3845           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3846                                            (const void **) values,
3847                                            ARRAYELTS (keys),
3848                                            &kCFTypeDictionaryKeyCallBacks,
3849                                            &kCFTypeDictionaryValueCallBacks);
3850           CFRelease (glyph_info);
3851         }
3852       if (attributes)
3853         {
3854           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3855           CFRelease (attributes);
3856         }
3857       CFRelease (string);
3858     }
3859   if (attr_string)
3860     {
3861       ctline = CTLineCreateWithAttributedString (attr_string);
3862       CFRelease (attr_string);
3863     }
3864   if (ctline)
3865     {
3866       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3868       if (CFArrayGetCount (runs) > 0)
3869         {
3870           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3871           CFDictionaryRef attributes = CTRunGetAttributes (run);
3873           if (attributes)
3874             {
3875               CTFontRef font_in_run =
3876                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3878               if (font_in_run
3879                   && mac_font_equal_in_postscript_name (font_in_run, font))
3880                 {
3881                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3882                   if (result >= CTFontGetGlyphCount (font))
3883                     result = kCGFontIndexInvalid;
3884                 }
3885             }
3886         }
3887       CFRelease (ctline);
3888     }
3890   return result;
3892 #endif
3894 static CFArrayRef
3895 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3897   CFArrayRef result = NULL;
3899 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3900 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3901   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3902 #endif
3903     {
3904       CTFontRef user_font =
3905         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3907       if (user_font)
3908         {
3909           CFArrayRef languages =
3910             CFArrayCreate (NULL, (const void **) &language, 1,
3911                            &kCFTypeArrayCallBacks);
3913           if (languages)
3914             {
3915               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3916                                                                  languages);
3917               CFRelease (languages);
3918             }
3919           CFRelease (user_font);
3920         }
3921     }
3922 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3923   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3924 #endif
3925 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3926 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3927     {
3928       CFIndex i;
3930       for (i = 0; macfont_language_default_font_names[i].language; i++)
3931         {
3932           if (CFEqual (macfont_language_default_font_names[i].language,
3933                        language))
3934             {
3935               CFMutableArrayRef descriptors =
3936                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3938               if (descriptors)
3939                 {
3940                   CFIndex j;
3942                   for (j = 0;
3943                        macfont_language_default_font_names[i].font_names[j];
3944                        j++)
3945                     {
3946                       CFDictionaryRef attributes =
3947                         CFDictionaryCreate (NULL,
3948                                             ((const void **)
3949                                              &kCTFontNameAttribute),
3950                                             ((const void **)
3951                                              &macfont_language_default_font_names[i].font_names[j]),
3952                                             1, &kCFTypeDictionaryKeyCallBacks,
3953                                             &kCFTypeDictionaryValueCallBacks);
3955                       if (attributes)
3956                         {
3957                           CTFontDescriptorRef pat_desc =
3958                             CTFontDescriptorCreateWithAttributes (attributes);
3960                           if (pat_desc)
3961                             {
3962                               CTFontDescriptorRef descriptor =
3963                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3965                               if (descriptor)
3966                                 {
3967                                   CFArrayAppendValue (descriptors, descriptor);
3968                                   CFRelease (descriptor);
3969                                 }
3970                               CFRelease (pat_desc);
3971                             }
3972                           CFRelease (attributes);
3973                         }
3974                     }
3975                   result = descriptors;
3976                 }
3977               break;
3978             }
3979         }
3980     }
3981 #endif
3983   return result;
3986 static CFStringRef
3987 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3988                                                       CFArrayRef languages)
3990   CFStringRef result = NULL;
3991   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3992   CFArrayRef descriptors =
3993     mac_font_copy_default_descriptors_for_language (language);
3995   if (descriptors)
3996     {
3997       CFIndex i, count = CFArrayGetCount (descriptors);
3999       for (i = 0; i < count; i++)
4000         {
4001           CTFontDescriptorRef descriptor =
4002             CFArrayGetValueAtIndex (descriptors, i);
4004           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4005                                                         Qnil, languages))
4006             {
4007               CFStringRef family =
4008                 CTFontDescriptorCopyAttribute (descriptor,
4009                                                kCTFontFamilyNameAttribute);
4010               if (family)
4011                 {
4012                   if (!CFStringHasPrefix (family, CFSTR ("."))
4013                       && !CFEqual (family, CFSTR ("LastResort")))
4014                     {
4015                       result = family;
4016                       break;
4017                     }
4018                   else
4019                     CFRelease (family);
4020                 }
4021             }
4022         }
4023       CFRelease (descriptors);
4024     }
4026   return result;
4029 void *
4030 macfont_get_nsctfont (struct font *font)
4032   struct macfont_info *macfont_info = (struct macfont_info *) font;
4033   CTFontRef macfont = macfont_info->macfont;
4035   return (void *) macfont;
4038 void
4039 mac_register_font_driver (struct frame *f)
4041   register_font_driver (&macfont_driver, f);
4045 void
4046 syms_of_macfont (void)
4048   /* Core Text, for Mac OS X.  */
4049   DEFSYM (Qmac_ct, "mac-ct");
4050   macfont_driver.type = Qmac_ct;
4051   register_font_driver (&macfont_driver, NULL);
4053   /* The font property key specifying the font design destination.  The
4054      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4055      text.  (See the documentation of X Logical Font Description
4056      Conventions.)  In the Mac font driver, 1 means the screen font is
4057      used for calculating some glyph metrics.  You can see the
4058      difference with Monaco 8pt or 9pt, for example.  */
4059   DEFSYM (QCdestination, ":destination");
4061   /* The boolean-valued font property key specifying the use of leading.  */
4062   DEFSYM (QCminspace, ":minspace");
4064   macfont_family_cache = Qnil;
4065   staticpro (&macfont_family_cache);