Merge from origin/emacs-25
[emacs.git] / src / macfont.m
blobd9bad034fe963802fbc200bcca51b72990f02b67
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);
2882           /* Stroke line width for text drawing is not correctly
2883              scaled on Retina display/HiDPI mode when drawn to screen
2884              (whereas it is correctly scaled when drawn to bitmaps),
2885              and synthetic bold looks thinner on such environments.
2886              Apple says there are no plans to address this issue
2887              (rdar://11644870) currently.  So we add a workaround.  */
2888 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
2889           CGContextSetLineWidth (context, synthetic_bold_factor * font_size
2890                                  * [[FRAME_NS_VIEW(f) window] backingScaleFactor]);
2891 #else
2892           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2893 #endif
2894           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2895         }
2896       if (no_antialias_p)
2897         CGContextSetShouldAntialias (context, false);
2899       CGContextSetTextMatrix (context, atfm);
2900       CGContextSetTextPosition (context, text_position.x, text_position.y);
2902 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2903       if (macfont_info->color_bitmap_p
2904 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2905           && CTFontDrawGlyphs != NULL
2906 #endif
2907           )
2908         {
2909           if (len > 0)
2910             {
2911               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2912                                 context);
2913             }
2914         }
2915       else
2916 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2917         {
2918           CGContextSetFont (context, macfont_info->cgfont);
2919           CGContextSetFontSize (context, font_size);
2920           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2921         }
2922     }
2925   xfree (glyphs);
2926   xfree (positions);
2927   CGContextRestoreGState (context);
2929   unblock_input ();
2931   return len;
2934 static Lisp_Object
2935 macfont_shape (Lisp_Object lgstring)
2937   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2938   struct macfont_info *macfont_info = (struct macfont_info *) font;
2939   CTFontRef macfont = macfont_info->macfont;
2940   ptrdiff_t glyph_len, len, i, j;
2941   CFIndex nonbmp_len;
2942   UniChar *unichars;
2943   CFIndex *nonbmp_indices;
2944   CFStringRef string;
2945   CFIndex used = 0;
2946   struct mac_glyph_layout *glyph_layouts;
2948   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2949   nonbmp_len = 0;
2950   for (i = 0; i < glyph_len; i++)
2951     {
2952       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2954       if (NILP (lglyph))
2955         break;
2956       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2957         nonbmp_len++;
2958     }
2960   len = i;
2962   if (INT_MAX / 2 < len)
2963     memory_full (SIZE_MAX);
2965   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2966   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2967   for (i = j = 0; i < len; i++)
2968     {
2969       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2971       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2972         {
2973           nonbmp_indices[j] = i + j;
2974           j++;
2975         }
2976     }
2977   nonbmp_indices[j] = len + j;  /* sentinel */
2979   block_input ();
2981   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2982                                                kCFAllocatorNull);
2983   if (string)
2984     {
2985       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2986       if (macfont_info->screen_font)
2987         used = mac_screen_font_shape (macfont_info->screen_font, string,
2988                                       glyph_layouts, glyph_len);
2989       else
2990         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2991       CFRelease (string);
2992     }
2994   unblock_input ();
2996   if (used == 0)
2997     return Qnil;
2999   block_input ();
3001   for (i = 0; i < used; i++)
3002     {
3003       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
3004       struct mac_glyph_layout *gl = glyph_layouts + i;
3005       EMACS_INT from, to;
3006       struct font_metrics metrics;
3007       int xoff, yoff, wadjust;
3009       if (NILP (lglyph))
3010         {
3011           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
3012           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
3013         }
3015       from = gl->comp_range.location;
3016       /* Convert UTF-16 index to UTF-32.  */
3017       j = 0;
3018       while (nonbmp_indices[j] < from)
3019         j++;
3020       from -= j;
3021       LGLYPH_SET_FROM (lglyph, from);
3023       to = gl->comp_range.location + gl->comp_range.length;
3024       /* Convert UTF-16 index to UTF-32.  */
3025       while (nonbmp_indices[j] < to)
3026         j++;
3027       to -= j;
3028       LGLYPH_SET_TO (lglyph, to - 1);
3030       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3031          the composition is trivial.  */
3032       {
3033         UTF32Char c;
3035         if (unichars[gl->string_index] >= 0xD800
3036             && unichars[gl->string_index] < 0xDC00)
3037           c = (((unichars[gl->string_index] - 0xD800) << 10)
3038                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3039         else
3040           c = unichars[gl->string_index];
3041         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3042           c = 0;
3043         LGLYPH_SET_CHAR (lglyph, c);
3044       }
3046       {
3047         unsigned long cc = gl->glyph_id;
3048         LGLYPH_SET_CODE (lglyph, cc);
3049       }
3051       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3052       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3053       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3054       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3055       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3056       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3058       xoff = lround (gl->advance_delta);
3059       yoff = lround (- gl->baseline_delta);
3060       wadjust = lround (gl->advance);
3061       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3062         {
3063           Lisp_Object vec;
3065           vec = Fmake_vector (make_number (3), Qnil);
3066           ASET (vec, 0, make_number (xoff));
3067           ASET (vec, 1, make_number (yoff));
3068           ASET (vec, 2, make_number (wadjust));
3069           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3070         }
3071     }
3073   unblock_input ();
3075   return make_number (used);
3078 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3079 typedef UInt8 UINT24[3];
3081 #pragma pack(push, 1)
3082 struct variation_selector_record
3084   UINT24 var_selector;
3085   UInt32 default_uvs_offset, non_default_uvs_offset;
3087 struct uvs_table
3089   UInt16 format;
3090   UInt32 length, num_var_selector_records;
3091   struct variation_selector_record variation_selector_records[1];
3093 #define SIZEOF_UVS_TABLE_HEADER                                         \
3094   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3096 struct unicode_value_range
3098   UINT24 start_unicode_value;
3099   UInt8 additional_count;
3101 struct default_uvs_table {
3102   UInt32 num_unicode_value_ranges;
3103   struct unicode_value_range unicode_value_ranges[1];
3105 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3106   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3108 struct uvs_mapping
3110   UINT24 unicode_value;
3111   UInt16 glyph_id;
3113 struct non_default_uvs_table
3115   UInt32 num_uvs_mappings;
3116   struct uvs_mapping uvs_mappings[1];
3118 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3119   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3120 #pragma pack(pop)
3122 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3123 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3124    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3125    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3126 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3127 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3128 /* Succeeding one byte should also be accessible.  */
3129 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3130 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3132 /* Return UVS subtable for the specified FONT.  If the subtable is not
3133    found or ill-formatted, then return NULL.  */
3135 static CFDataRef
3136 mac_font_copy_uvs_table (CTFontRef font)
3138   CFDataRef cmap_table, uvs_table = NULL;
3140   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3141                                 kCTFontTableOptionNoOptions);
3142   if (cmap_table)
3143     {
3144       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3145       struct uvs_table *uvs;
3146       struct variation_selector_record *records;
3147       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3149 #if __LP64__
3150       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3151         goto finish;
3152 #endif
3154       cmap_len = CFDataGetLength (cmap_table);
3155       if (sizeof_sfntCMapHeader > cmap_len)
3156         goto finish;
3158       ntables = BUINT16_VALUE (cmap->numTables);
3159       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3160                      / sizeof_sfntCMapEncoding))
3161         goto finish;
3163       for (i = 0; i < ntables; i++)
3164         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3165              == kFontUnicodePlatform)
3166             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3167                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3168           {
3169             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3170             break;
3171           }
3172       if (i == ntables
3173           || uvs_offset > cmap_len
3174           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3175         goto finish;
3177       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3178       uvs_len = BUINT32_VALUE (uvs->length);
3179       if (uvs_len > cmap_len - uvs_offset
3180           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3181         goto finish;
3183       if (BUINT16_VALUE (uvs->format) != 14)
3184         goto finish;
3186       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3187       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3188                       / sizeof (struct variation_selector_record)))
3189         goto finish;
3191       records = uvs->variation_selector_records;
3192       for (i = 0; i < nrecords; i++)
3193         {
3194           UInt32 default_uvs_offset, non_default_uvs_offset;
3196           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3197           if (default_uvs_offset)
3198             {
3199               struct default_uvs_table *default_uvs;
3200               UInt32 nranges;
3202               if (default_uvs_offset > uvs_len
3203                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3204                       > uvs_len - default_uvs_offset))
3205                 goto finish;
3207               default_uvs = ((struct default_uvs_table *)
3208                              ((UInt8 *) uvs + default_uvs_offset));
3209               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3210               if (nranges > ((uvs_len - default_uvs_offset
3211                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3212                              / sizeof (struct unicode_value_range)))
3213                 goto finish;
3214               /* Now 2 * nranges can't overflow, so we can safely use
3215                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3216                  mac_font_get_glyphs_for_variants.  */
3217             }
3219           non_default_uvs_offset =
3220             BUINT32_VALUE (records[i].non_default_uvs_offset);
3221           if (non_default_uvs_offset)
3222             {
3223               struct non_default_uvs_table *non_default_uvs;
3224               UInt32 nmappings;
3226               if (non_default_uvs_offset > uvs_len
3227                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3228                       > uvs_len - non_default_uvs_offset))
3229                 goto finish;
3231               non_default_uvs = ((struct non_default_uvs_table *)
3232                                  ((UInt8 *) uvs + non_default_uvs_offset));
3233               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3234               if (nmappings > ((uvs_len - non_default_uvs_offset
3235                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3236                                / sizeof (struct uvs_mapping)))
3237                 goto finish;
3238               /* Now 2 * nmappings can't overflow, so we can safely
3239                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3240                  in mac_font_get_glyphs_for_variants.  */
3241             }
3242         }
3244       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3246     finish:
3247       CFRelease (cmap_table);
3248     }
3250   return uvs_table;
3253 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3254    sequence consisting of the given base character C and each
3255    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3256    result (explained below) into the corresponding GLYPHS[i].  If the
3257    entry is found in the Default UVS Table, then the result is 0.  If
3258    the entry is found in the Non-Default UVS Table, then the result is
3259    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3260    elements in SELECTORS must be sorted in strictly increasing
3261    order.  */
3263 static void
3264 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3265                                   const UTF32Char selectors[], CGGlyph glyphs[],
3266                                   CFIndex count)
3268   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3269   struct variation_selector_record *records = uvs->variation_selector_records;
3270   CFIndex i;
3271   UInt32 ir, nrecords;
3272   dispatch_queue_t queue =
3273     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3274   dispatch_group_t group = dispatch_group_create ();
3276   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3277   i = 0;
3278   ir = 0;
3279   while (i < count && ir < nrecords)
3280     {
3281       UInt32 default_uvs_offset, non_default_uvs_offset;
3283       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3284         {
3285           glyphs[i++] = kCGFontIndexInvalid;
3286           continue;
3287         }
3288       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3289         {
3290           ir++;
3291           continue;
3292         }
3294       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3295       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3296       non_default_uvs_offset =
3297         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3298       dispatch_group_async (group, queue, ^{
3299           glyphs[i] = kCGFontIndexInvalid;
3301           if (default_uvs_offset)
3302             {
3303               struct default_uvs_table *default_uvs =
3304                 (struct default_uvs_table *) ((UInt8 *) uvs
3305                                               + default_uvs_offset);
3306               struct unicode_value_range *ranges =
3307                 default_uvs->unicode_value_ranges;
3308               UInt32 lo, hi;
3310               lo = 0;
3311               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3312               while (lo < hi)
3313                 {
3314                   UInt32 mid = (lo + hi) / 2;
3316                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3317                     hi = mid;
3318                   else
3319                     lo = mid + 1;
3320                 }
3321               if (hi > 0
3322                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3323                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3324                 glyphs[i] = 0;
3325             }
3327           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3328             {
3329               struct non_default_uvs_table *non_default_uvs =
3330                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3331                                                   + non_default_uvs_offset);
3332               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3333               UInt32 lo, hi;
3335               lo = 0;
3336               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3337               while (lo < hi)
3338                 {
3339                   UInt32 mid = (lo + hi) / 2;
3341                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3342                     hi = mid;
3343                   else
3344                     lo = mid + 1;
3345                 }
3346               if (hi > 0 &&
3347                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3348                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3349             }
3350         });
3351       i++;
3352       ir++;
3353     }
3354   while (i < count)
3355     glyphs[i++] = kCGFontIndexInvalid;
3356   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3357   dispatch_release (group);
3360 static int
3361 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3363   CFDataRef uvs_table;
3364   CTCharacterCollection uvs_collection;
3365   int i, n = 0;
3367   block_input ();
3368   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3370   if (uvs_table)
3371     {
3372       UTF32Char selectors[256];
3373       CGGlyph glyphs[256];
3375       for (i = 0; i < 16; i++)
3376         selectors[i] = 0xFE00 + i;
3377       for (; i < 256; i++)
3378         selectors[i] = 0xE0100 + (i - 16);
3379       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3380       for (i = 0; i < 256; i++)
3381         {
3382           CGGlyph glyph = glyphs[i];
3384           if (uvs_collection != kCTCharacterCollectionIdentityMapping
3385               && glyph != kCGFontIndexInvalid)
3386             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3387           if (glyph == kCGFontIndexInvalid)
3388             variations[i] = 0;
3389           else
3390             {
3391               variations[i] = (glyph ? glyph
3392                                : macfont_get_glyph_for_character (font, c));
3393               n++;
3394             }
3395         }
3396     }
3397   unblock_input ();
3399   return n;
3402 static const char *const macfont_booleans[] = {
3403   ":antialias",
3404   ":minspace",
3405   NULL,
3408 static const char *const macfont_non_booleans[] = {
3409   ":lang",
3410   ":script",
3411   ":destination",
3412   NULL,
3415 static void
3416 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3418   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3421 static Boolean
3422 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3423                                         CFArrayRef languages)
3425   Boolean result = true;
3426   CFArrayRef desc_languages =
3427     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3429   if (desc_languages == NULL)
3430     result = false;
3431   else
3432     {
3433       CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3434       CFIndex i, languages_count = CFArrayGetCount (languages);
3436       for (i = 0; i < languages_count; i++)
3437         {
3438           CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3440           if (!CFArrayContainsValue (desc_languages, range, language)
3441               /* PingFang SC contains "zh" and "zh-Hant" as covered
3442                  languages, but does not contain "zh-Hans".  */
3443               && !(CFEqual (language, CFSTR ("zh-Hans"))
3444                    && CFArrayContainsValue (desc_languages, range,
3445                                             CFSTR ("zh"))))
3446             {
3447               result = false;
3448               break;
3449             }
3450         }
3451       CFRelease (desc_languages);
3452     }
3454   return result;
3457 static CFStringRef
3458 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3460   CFStringRef result = NULL;
3461   CFStringRef charset_string =
3462     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3464   if (charset_string && CFStringGetLength (charset_string) > 0)
3465     {
3466       CFStringRef keys[] = {
3467 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3468         kCTLanguageAttributeName
3469 #else
3470         CFSTR ("NSLanguage")
3471 #endif
3472       };
3473       CFTypeRef values[] = {NULL};
3474       CFIndex num_values = 0;
3475       CFArrayRef languages
3476         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3478       if (languages && CFArrayGetCount (languages) > 0)
3479         {
3480           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3481             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3482           else
3483             {
3484               CFCharacterSetRef charset =
3485                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3487               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3488             }
3489         }
3490       if (result == NULL)
3491         {
3492           CFAttributedStringRef attr_string = NULL;
3493           CTLineRef ctline = NULL;
3494           CFDictionaryRef attrs
3495             = CFDictionaryCreate (NULL, (const void **) keys,
3496                                   (const void **) values, num_values,
3497                                   &kCFTypeDictionaryKeyCallBacks,
3498                                   &kCFTypeDictionaryValueCallBacks);
3500           if (attrs)
3501             {
3502               attr_string = CFAttributedStringCreate (NULL, charset_string,
3503                                                       attrs);
3504               CFRelease (attrs);
3505             }
3506           if (attr_string)
3507             {
3508               ctline = CTLineCreateWithAttributedString (attr_string);
3509               CFRelease (attr_string);
3510             }
3511           if (ctline)
3512             {
3513               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3514               CFIndex i, nruns = CFArrayGetCount (runs);
3515               CTFontRef font;
3517               for (i = 0; i < nruns; i++)
3518                 {
3519                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3520                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3521                   CTFontRef font_in_run;
3523                   if (attributes == NULL)
3524                     break;
3525                   font_in_run =
3526                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3527                   if (font_in_run == NULL)
3528                     break;
3529                   if (i == 0)
3530                     font = font_in_run;
3531                   else if (!mac_font_equal_in_postscript_name (font,
3532                                                                font_in_run))
3533                     break;
3534                 }
3535               if (nruns > 0 && i == nruns)
3536                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3537               CFRelease (ctline);
3538             }
3539         }
3540     }
3542   return result;
3545 static inline double
3546 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3548   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3549                                      &glyph, NULL, 1);
3552 static inline CGRect
3553 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3555   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3556                                           &glyph, NULL, 1);
3559 static CFArrayRef
3560 mac_font_create_available_families (void)
3562   CFMutableArrayRef families = NULL;
3563   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3565   if (orig_families)
3566     {
3567       CFIndex i, count = CFArrayGetCount (orig_families);
3569       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3570       if (families)
3571         for (i = 0; i < count; i++)
3572           {
3573             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3575             if (!CFStringHasPrefix (family, CFSTR ("."))
3576                 && (CTFontManagerCompareFontFamilyNames (family,
3577                                                          CFSTR ("LastResort"),
3578                                                          NULL)
3579                     != kCFCompareEqualTo))
3580               CFArrayAppendValue (families, family);
3581           }
3582       CFRelease (orig_families);
3583     }
3585   return families;
3588 static Boolean
3589 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3591   Boolean result;
3592   CFStringRef name1, name2;
3594   if (font1 == font2)
3595     return true;
3597   result = false;
3598   name1 = CTFontCopyPostScriptName (font1);
3599   if (name1)
3600     {
3601       name2 = CTFontCopyPostScriptName (font2);
3602       if (name2)
3603         {
3604           result = CFEqual (name1, name2);
3605           CFRelease (name2);
3606         }
3607       CFRelease (name1);
3608     }
3610   return result;
3613 static CTLineRef
3614 mac_font_create_line_with_string_and_font (CFStringRef string,
3615                                            CTFontRef macfont)
3617   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3618   CFTypeRef values[] = {NULL, NULL};
3619   CFDictionaryRef attributes = NULL;
3620   CFAttributedStringRef attr_string = NULL;
3621   CTLineRef ctline = NULL;
3622   float float_zero = 0.0f;
3624   values[0] = macfont;
3625   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3626   if (values[1])
3627     {
3628       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3629                                        (const void **) values,
3630                                        ARRAYELTS (keys),
3631                                        &kCFTypeDictionaryKeyCallBacks,
3632                                        &kCFTypeDictionaryValueCallBacks);
3633       CFRelease (values[1]);
3634     }
3635   if (attributes)
3636     {
3637       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3638       CFRelease (attributes);
3639     }
3640   if (attr_string)
3641     {
3642       ctline = CTLineCreateWithAttributedString (attr_string);
3643       CFRelease (attr_string);
3644     }
3645   if (ctline)
3646     {
3647       /* Abandon if ctline contains some fonts other than the
3648          specified one.  */
3649       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3650       CFIndex i, nruns = CFArrayGetCount (runs);
3652       for (i = 0; i < nruns; i++)
3653         {
3654           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3655           CFDictionaryRef attributes = CTRunGetAttributes (run);
3656           CTFontRef font_in_run;
3658           if (attributes == NULL)
3659             break;
3660           font_in_run =
3661             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3662           if (font_in_run == NULL)
3663             break;
3664           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3665             break;
3666         }
3667       if (i < nruns)
3668         {
3669           CFRelease (ctline);
3670           ctline = NULL;
3671         }
3672     }
3674   return ctline;
3677 static CFIndex
3678 mac_font_shape (CTFontRef font, CFStringRef string,
3679                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3681   CFIndex used, result = 0;
3682   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3684   if (ctline == NULL)
3685     return 0;
3687   used = CTLineGetGlyphCount (ctline);
3688   if (used <= glyph_len)
3689     {
3690       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3691       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3692       CGFloat total_advance = 0;
3693       CFIndex total_glyph_count = 0;
3695       for (k = 0; k < ctrun_count; k++)
3696         {
3697           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3698           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3699           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3700           CFRange string_range, comp_range, range;
3701           CFIndex *permutation;
3703           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3704             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3705           else
3706             permutation = NULL;
3708 #define RIGHT_TO_LEFT_P permutation
3710           /* Now the `comp_range' member of struct mac_glyph_layout is
3711              temporarily used as a work area such that:
3712              glbuf[i].comp_range.location =
3713              min {compRange[i + 1].location, ...,
3714                      compRange[glyph_count - 1].location,
3715                      maxRange (stringRangeForCTRun)}
3716              glbuf[i].comp_range.length = maxRange (compRange[i])
3717              where compRange[i] is the range of composed characters
3718              containing i-th glyph.  */
3719           string_range = CTRunGetStringRange (ctrun);
3720           min_location = string_range.location + string_range.length;
3721           for (i = 0; i < glyph_count; i++)
3722             {
3723               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3724               CFIndex glyph_index;
3725               CFRange rng;
3727               if (!RIGHT_TO_LEFT_P)
3728                 glyph_index = glyph_count - i - 1;
3729               else
3730                 glyph_index = i;
3731               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3732                                      &gl->string_index);
3733               rng =
3734                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3735                                                              gl->string_index);
3736               gl->comp_range.location = min_location;
3737               gl->comp_range.length = rng.location + rng.length;
3738               if (rng.location < min_location)
3739                 min_location = rng.location;
3740             }
3742           /* Fill the `comp_range' member of struct mac_glyph_layout,
3743              and setup a permutation for right-to-left text.  */
3744           comp_range = CFRangeMake (string_range.location, 0);
3745           range = CFRangeMake (0, 0);
3746           while (1)
3747             {
3748               struct mac_glyph_layout *gl =
3749                 glbuf + range.location + range.length;
3751               if (gl->comp_range.length
3752                   > comp_range.location + comp_range.length)
3753                 comp_range.length = gl->comp_range.length - comp_range.location;
3754               min_location = gl->comp_range.location;
3755               range.length++;
3757               if (min_location >= comp_range.location + comp_range.length)
3758                 {
3759                   comp_range.length = min_location - comp_range.location;
3760                   for (i = 0; i < range.length; i++)
3761                     {
3762                       glbuf[range.location + i].comp_range = comp_range;
3763                       if (RIGHT_TO_LEFT_P)
3764                         permutation[range.location + i] =
3765                           range.location + range.length - i - 1;
3766                     }
3768                   comp_range = CFRangeMake (min_location, 0);
3769                   range.location += range.length;
3770                   range.length = 0;
3771                   if (range.location == glyph_count)
3772                     break;
3773                 }
3774             }
3776           /* Then fill the remaining members.  */
3777           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3778                range.location++)
3779             {
3780               struct mac_glyph_layout *gl;
3781               CGPoint position;
3782               CGFloat max_x;
3784               if (!RIGHT_TO_LEFT_P)
3785                 gl = glbuf + range.location;
3786               else
3787                 {
3788                   CFIndex src, dest;
3790                   src = glyph_count - 1 - range.location;
3791                   dest = permutation[src];
3792                   gl = glbuf + dest;
3793                   if (src < dest)
3794                     {
3795                       CFIndex tmp = gl->string_index;
3797                       gl->string_index = glbuf[src].string_index;
3798                       glbuf[src].string_index = tmp;
3799                     }
3800                 }
3801               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3803               CTRunGetPositions (ctrun, range, &position);
3804               max_x = position.x + CTRunGetTypographicBounds (ctrun, range,
3805                                                               NULL, NULL, NULL);
3806               max_x = max (max_x, total_advance);
3807               gl->advance_delta = position.x - total_advance;
3808               gl->baseline_delta = position.y;
3809               gl->advance = max_x - total_advance;
3810               total_advance = max_x;
3811             }
3813           if (RIGHT_TO_LEFT_P)
3814             xfree (permutation);
3816 #undef RIGHT_TO_LEFT_P
3818           total_glyph_count += glyph_count;
3819         }
3821       result = used;
3822     }
3823   CFRelease (ctline);
3825   return result;
3828 /* The function below seems to cause a memory leak for the CFString
3829    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3830    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3831 #if USE_CT_GLYPH_INFO
3832 static CGGlyph
3833 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3834                               CGFontIndex cid)
3836   CGGlyph result = kCGFontIndexInvalid;
3837   UniChar characters[] = {0xfffd};
3838   CFStringRef string;
3839   CFAttributedStringRef attr_string = NULL;
3840   CTLineRef ctline = NULL;
3842   string = CFStringCreateWithCharacters (NULL, characters,
3843                                          ARRAYELTS (characters));
3845   if (string)
3846     {
3847       CTGlyphInfoRef glyph_info =
3848         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3849       CFDictionaryRef attributes = NULL;
3851       if (glyph_info)
3852         {
3853           CFStringRef keys[] = {kCTFontAttributeName,
3854                                 kCTGlyphInfoAttributeName};
3855           CFTypeRef values[] = {font, glyph_info};
3857           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3858                                            (const void **) values,
3859                                            ARRAYELTS (keys),
3860                                            &kCFTypeDictionaryKeyCallBacks,
3861                                            &kCFTypeDictionaryValueCallBacks);
3862           CFRelease (glyph_info);
3863         }
3864       if (attributes)
3865         {
3866           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3867           CFRelease (attributes);
3868         }
3869       CFRelease (string);
3870     }
3871   if (attr_string)
3872     {
3873       ctline = CTLineCreateWithAttributedString (attr_string);
3874       CFRelease (attr_string);
3875     }
3876   if (ctline)
3877     {
3878       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3880       if (CFArrayGetCount (runs) > 0)
3881         {
3882           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3883           CFDictionaryRef attributes = CTRunGetAttributes (run);
3885           if (attributes)
3886             {
3887               CTFontRef font_in_run =
3888                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3890               if (font_in_run
3891                   && mac_font_equal_in_postscript_name (font_in_run, font))
3892                 {
3893                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3894                   if (result >= CTFontGetGlyphCount (font))
3895                     result = kCGFontIndexInvalid;
3896                 }
3897             }
3898         }
3899       CFRelease (ctline);
3900     }
3902   return result;
3904 #endif
3906 static CFArrayRef
3907 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3909   CFArrayRef result = NULL;
3911 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3912 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3913   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3914 #endif
3915     {
3916       CTFontRef user_font =
3917         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3919       if (user_font)
3920         {
3921           CFArrayRef languages =
3922             CFArrayCreate (NULL, (const void **) &language, 1,
3923                            &kCFTypeArrayCallBacks);
3925           if (languages)
3926             {
3927               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3928                                                                  languages);
3929               CFRelease (languages);
3930             }
3931           CFRelease (user_font);
3932         }
3933     }
3934 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3935   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3936 #endif
3937 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3938 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3939     {
3940       CFIndex i;
3942       for (i = 0; macfont_language_default_font_names[i].language; i++)
3943         {
3944           if (CFEqual (macfont_language_default_font_names[i].language,
3945                        language))
3946             {
3947               CFMutableArrayRef descriptors =
3948                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3950               if (descriptors)
3951                 {
3952                   CFIndex j;
3954                   for (j = 0;
3955                        macfont_language_default_font_names[i].font_names[j];
3956                        j++)
3957                     {
3958                       CFDictionaryRef attributes =
3959                         CFDictionaryCreate (NULL,
3960                                             ((const void **)
3961                                              &kCTFontNameAttribute),
3962                                             ((const void **)
3963                                              &macfont_language_default_font_names[i].font_names[j]),
3964                                             1, &kCFTypeDictionaryKeyCallBacks,
3965                                             &kCFTypeDictionaryValueCallBacks);
3967                       if (attributes)
3968                         {
3969                           CTFontDescriptorRef pat_desc =
3970                             CTFontDescriptorCreateWithAttributes (attributes);
3972                           if (pat_desc)
3973                             {
3974                               CTFontDescriptorRef descriptor =
3975                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3977                               if (descriptor)
3978                                 {
3979                                   CFArrayAppendValue (descriptors, descriptor);
3980                                   CFRelease (descriptor);
3981                                 }
3982                               CFRelease (pat_desc);
3983                             }
3984                           CFRelease (attributes);
3985                         }
3986                     }
3987                   result = descriptors;
3988                 }
3989               break;
3990             }
3991         }
3992     }
3993 #endif
3995   return result;
3998 static CFStringRef
3999 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
4000                                                       CFArrayRef languages)
4002   CFStringRef result = NULL;
4003   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
4004   CFArrayRef descriptors =
4005     mac_font_copy_default_descriptors_for_language (language);
4007   if (descriptors)
4008     {
4009       CFIndex i, count = CFArrayGetCount (descriptors);
4011       for (i = 0; i < count; i++)
4012         {
4013           CTFontDescriptorRef descriptor =
4014             CFArrayGetValueAtIndex (descriptors, i);
4016           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4017                                                         Qnil, languages))
4018             {
4019               CFStringRef family =
4020                 CTFontDescriptorCopyAttribute (descriptor,
4021                                                kCTFontFamilyNameAttribute);
4022               if (family)
4023                 {
4024                   if (!CFStringHasPrefix (family, CFSTR ("."))
4025                       && !CFEqual (family, CFSTR ("LastResort")))
4026                     {
4027                       result = family;
4028                       break;
4029                     }
4030                   else
4031                     CFRelease (family);
4032                 }
4033             }
4034         }
4035       CFRelease (descriptors);
4036     }
4038   return result;
4041 void *
4042 macfont_get_nsctfont (struct font *font)
4044   struct macfont_info *macfont_info = (struct macfont_info *) font;
4045   CTFontRef macfont = macfont_info->macfont;
4047   return (void *) macfont;
4050 void
4051 mac_register_font_driver (struct frame *f)
4053   register_font_driver (&macfont_driver, f);
4057 void
4058 syms_of_macfont (void)
4060   /* Core Text, for Mac OS X.  */
4061   DEFSYM (Qmac_ct, "mac-ct");
4062   macfont_driver.type = Qmac_ct;
4063   register_font_driver (&macfont_driver, NULL);
4065   /* The font property key specifying the font design destination.  The
4066      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4067      text.  (See the documentation of X Logical Font Description
4068      Conventions.)  In the Mac font driver, 1 means the screen font is
4069      used for calculating some glyph metrics.  You can see the
4070      difference with Monaco 8pt or 9pt, for example.  */
4071   DEFSYM (QCdestination, ":destination");
4073   /* The boolean-valued font property key specifying the use of leading.  */
4074   DEFSYM (QCminspace, ":minspace");
4076   macfont_family_cache = Qnil;
4077   staticpro (&macfont_family_cache);