(ls-lisp-insert-directory): Make -B work
[emacs.git] / src / macfont.m
blob45830e0ff8ab79ca052e6503a8dd62dbe42c5e13
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
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
22 #include <config.h>
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "frame.h"
27 #include "blockinput.h"
28 #include "character.h"
29 #include "charset.h"
30 #include "composite.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "termchar.h"
34 #include "nsgui.h"
35 #include "nsterm.h"
36 #include "macfont.h"
37 #include "macuvs.h"
39 #include <libkern/OSByteOrder.h>
41 static struct font_driver macfont_driver;
43 static double mac_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 unless its family is
2377              explicitly specified.  */
2378           if ((sym_traits & kCTFontTraitColorGlyphs) && NILP (family))
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 (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2860           if (!face)
2861             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2862         }
2863       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2864       CGContextFillRects (context, &background_rect, 1);
2865     }
2867   if (macfont_info->cgfont)
2868     {
2869       CGAffineTransform atfm;
2871       CGContextScaleCTM (context, 1, -1);
2872       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2873       if (macfont_info->synthetic_italic_p)
2874         atfm = synthetic_italic_atfm;
2875       else
2876         atfm = CGAffineTransformIdentity;
2877       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2878         {
2879           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2880           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2881           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2882         }
2883       if (no_antialias_p)
2884         CGContextSetShouldAntialias (context, false);
2886       CGContextSetTextMatrix (context, atfm);
2887       CGContextSetTextPosition (context, text_position.x, text_position.y);
2889 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2890       if (macfont_info->color_bitmap_p
2891 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2892           && CTFontDrawGlyphs != NULL
2893 #endif
2894           )
2895         {
2896           if (len > 0)
2897             {
2898               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2899                                 context);
2900             }
2901         }
2902       else
2903 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2904         {
2905           CGContextSetFont (context, macfont_info->cgfont);
2906           CGContextSetFontSize (context, font_size);
2907           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2908         }
2909     }
2912   xfree (glyphs);
2913   xfree (positions);
2914   CGContextRestoreGState (context);
2916   unblock_input ();
2918   return len;
2921 static Lisp_Object
2922 macfont_shape (Lisp_Object lgstring)
2924   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2925   struct macfont_info *macfont_info = (struct macfont_info *) font;
2926   CTFontRef macfont = macfont_info->macfont;
2927   ptrdiff_t glyph_len, len, i, j;
2928   CFIndex nonbmp_len;
2929   UniChar *unichars;
2930   CFIndex *nonbmp_indices;
2931   CFStringRef string;
2932   CFIndex used = 0;
2933   struct mac_glyph_layout *glyph_layouts;
2935   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2936   nonbmp_len = 0;
2937   for (i = 0; i < glyph_len; i++)
2938     {
2939       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2941       if (NILP (lglyph))
2942         break;
2943       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2944         nonbmp_len++;
2945     }
2947   len = i;
2949   if (INT_MAX / 2 < len)
2950     memory_full (SIZE_MAX);
2952   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2953   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2954   for (i = j = 0; i < len; i++)
2955     {
2956       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2958       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2959         {
2960           nonbmp_indices[j] = i + j;
2961           j++;
2962         }
2963     }
2964   nonbmp_indices[j] = len + j;  /* sentinel */
2966   block_input ();
2968   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2969                                                kCFAllocatorNull);
2970   if (string)
2971     {
2972       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2973       if (macfont_info->screen_font)
2974         used = mac_screen_font_shape (macfont_info->screen_font, string,
2975                                       glyph_layouts, glyph_len);
2976       else
2977         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2978       CFRelease (string);
2979     }
2981   unblock_input ();
2983   if (used == 0)
2984     return Qnil;
2986   block_input ();
2988   for (i = 0; i < used; i++)
2989     {
2990       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2991       struct mac_glyph_layout *gl = glyph_layouts + i;
2992       EMACS_INT from, to;
2993       struct font_metrics metrics;
2994       int xoff, yoff, wadjust;
2996       if (NILP (lglyph))
2997         {
2998           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2999           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
3000         }
3002       from = gl->comp_range.location;
3003       /* Convert UTF-16 index to UTF-32.  */
3004       j = 0;
3005       while (nonbmp_indices[j] < from)
3006         j++;
3007       from -= j;
3008       LGLYPH_SET_FROM (lglyph, from);
3010       to = gl->comp_range.location + gl->comp_range.length;
3011       /* Convert UTF-16 index to UTF-32.  */
3012       while (nonbmp_indices[j] < to)
3013         j++;
3014       to -= j;
3015       LGLYPH_SET_TO (lglyph, to - 1);
3017       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3018          the composition is trivial.  */
3019       {
3020         UTF32Char c;
3022         if (unichars[gl->string_index] >= 0xD800
3023             && unichars[gl->string_index] < 0xDC00)
3024           c = (((unichars[gl->string_index] - 0xD800) << 10)
3025                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3026         else
3027           c = unichars[gl->string_index];
3028         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3029           c = 0;
3030         LGLYPH_SET_CHAR (lglyph, c);
3031       }
3033       {
3034         unsigned long cc = gl->glyph_id;
3035         LGLYPH_SET_CODE (lglyph, cc);
3036       }
3038       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3039       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3040       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3041       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3042       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3043       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3045       xoff = lround (gl->advance_delta);
3046       yoff = lround (- gl->baseline_delta);
3047       wadjust = lround (gl->advance);
3048       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3049         {
3050           Lisp_Object vec;
3052           vec = Fmake_vector (make_number (3), Qnil);
3053           ASET (vec, 0, make_number (xoff));
3054           ASET (vec, 1, make_number (yoff));
3055           ASET (vec, 2, make_number (wadjust));
3056           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3057         }
3058     }
3060   unblock_input ();
3062   return make_number (used);
3065 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3066 typedef UInt8 UINT24[3];
3068 #pragma pack(push, 1)
3069 struct variation_selector_record
3071   UINT24 var_selector;
3072   UInt32 default_uvs_offset, non_default_uvs_offset;
3074 struct uvs_table
3076   UInt16 format;
3077   UInt32 length, num_var_selector_records;
3078   struct variation_selector_record variation_selector_records[1];
3080 #define SIZEOF_UVS_TABLE_HEADER                                         \
3081   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3083 struct unicode_value_range
3085   UINT24 start_unicode_value;
3086   UInt8 additional_count;
3088 struct default_uvs_table {
3089   UInt32 num_unicode_value_ranges;
3090   struct unicode_value_range unicode_value_ranges[1];
3092 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3093   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3095 struct uvs_mapping
3097   UINT24 unicode_value;
3098   UInt16 glyph_id;
3100 struct non_default_uvs_table
3102   UInt32 num_uvs_mappings;
3103   struct uvs_mapping uvs_mappings[1];
3105 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3106   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3107 #pragma pack(pop)
3109 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3110 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3111    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3112    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3113 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3114 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3115 /* Succeeding one byte should also be accessible.  */
3116 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3117 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3119 /* Return UVS subtable for the specified FONT.  If the subtable is not
3120    found or ill-formatted, then return NULL.  */
3122 static CFDataRef
3123 mac_font_copy_uvs_table (CTFontRef font)
3125   CFDataRef cmap_table, uvs_table = NULL;
3127   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3128                                 kCTFontTableOptionNoOptions);
3129   if (cmap_table)
3130     {
3131       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3132       struct uvs_table *uvs;
3133       struct variation_selector_record *records;
3134       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3136 #if __LP64__
3137       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3138         goto finish;
3139 #endif
3141       cmap_len = CFDataGetLength (cmap_table);
3142       if (sizeof_sfntCMapHeader > cmap_len)
3143         goto finish;
3145       ntables = BUINT16_VALUE (cmap->numTables);
3146       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3147                      / sizeof_sfntCMapEncoding))
3148         goto finish;
3150       for (i = 0; i < ntables; i++)
3151         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3152              == kFontUnicodePlatform)
3153             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3154                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3155           {
3156             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3157             break;
3158           }
3159       if (i == ntables
3160           || uvs_offset > cmap_len
3161           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3162         goto finish;
3164       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3165       uvs_len = BUINT32_VALUE (uvs->length);
3166       if (uvs_len > cmap_len - uvs_offset
3167           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3168         goto finish;
3170       if (BUINT16_VALUE (uvs->format) != 14)
3171         goto finish;
3173       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3174       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3175                       / sizeof (struct variation_selector_record)))
3176         goto finish;
3178       records = uvs->variation_selector_records;
3179       for (i = 0; i < nrecords; i++)
3180         {
3181           UInt32 default_uvs_offset, non_default_uvs_offset;
3183           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3184           if (default_uvs_offset)
3185             {
3186               struct default_uvs_table *default_uvs;
3187               UInt32 nranges;
3189               if (default_uvs_offset > uvs_len
3190                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3191                       > uvs_len - default_uvs_offset))
3192                 goto finish;
3194               default_uvs = ((struct default_uvs_table *)
3195                              ((UInt8 *) uvs + default_uvs_offset));
3196               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3197               if (nranges > ((uvs_len - default_uvs_offset
3198                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3199                              / sizeof (struct unicode_value_range)))
3200                 goto finish;
3201               /* Now 2 * nranges can't overflow, so we can safely use
3202                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3203                  mac_font_get_glyphs_for_variants.  */
3204             }
3206           non_default_uvs_offset =
3207             BUINT32_VALUE (records[i].non_default_uvs_offset);
3208           if (non_default_uvs_offset)
3209             {
3210               struct non_default_uvs_table *non_default_uvs;
3211               UInt32 nmappings;
3213               if (non_default_uvs_offset > uvs_len
3214                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3215                       > uvs_len - non_default_uvs_offset))
3216                 goto finish;
3218               non_default_uvs = ((struct non_default_uvs_table *)
3219                                  ((UInt8 *) uvs + non_default_uvs_offset));
3220               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3221               if (nmappings > ((uvs_len - non_default_uvs_offset
3222                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3223                                / sizeof (struct uvs_mapping)))
3224                 goto finish;
3225               /* Now 2 * nmappings can't overflow, so we can safely
3226                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3227                  in mac_font_get_glyphs_for_variants.  */
3228             }
3229         }
3231       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3233     finish:
3234       CFRelease (cmap_table);
3235     }
3237   return uvs_table;
3240 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3241    sequence consisting of the given base character C and each
3242    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3243    result (explained below) into the corresponding GLYPHS[i].  If the
3244    entry is found in the Default UVS Table, then the result is 0.  If
3245    the entry is found in the Non-Default UVS Table, then the result is
3246    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3247    elements in SELECTORS must be sorted in strictly increasing
3248    order.  */
3250 static void
3251 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3252                                   const UTF32Char selectors[], CGGlyph glyphs[],
3253                                   CFIndex count)
3255   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3256   struct variation_selector_record *records = uvs->variation_selector_records;
3257   CFIndex i;
3258   UInt32 ir, nrecords;
3259   dispatch_queue_t queue =
3260     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3261   dispatch_group_t group = dispatch_group_create ();
3263   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3264   i = 0;
3265   ir = 0;
3266   while (i < count && ir < nrecords)
3267     {
3268       UInt32 default_uvs_offset, non_default_uvs_offset;
3270       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3271         {
3272           glyphs[i++] = kCGFontIndexInvalid;
3273           continue;
3274         }
3275       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3276         {
3277           ir++;
3278           continue;
3279         }
3281       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3282       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3283       non_default_uvs_offset =
3284         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3285       dispatch_group_async (group, queue, ^{
3286           glyphs[i] = kCGFontIndexInvalid;
3288           if (default_uvs_offset)
3289             {
3290               struct default_uvs_table *default_uvs =
3291                 (struct default_uvs_table *) ((UInt8 *) uvs
3292                                               + default_uvs_offset);
3293               struct unicode_value_range *ranges =
3294                 default_uvs->unicode_value_ranges;
3295               UInt32 lo, hi;
3297               lo = 0;
3298               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3299               while (lo < hi)
3300                 {
3301                   UInt32 mid = (lo + hi) / 2;
3303                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3304                     hi = mid;
3305                   else
3306                     lo = mid + 1;
3307                 }
3308               if (hi > 0
3309                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3310                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3311                 glyphs[i] = 0;
3312             }
3314           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3315             {
3316               struct non_default_uvs_table *non_default_uvs =
3317                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3318                                                   + non_default_uvs_offset);
3319               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3320               UInt32 lo, hi;
3322               lo = 0;
3323               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3324               while (lo < hi)
3325                 {
3326                   UInt32 mid = (lo + hi) / 2;
3328                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3329                     hi = mid;
3330                   else
3331                     lo = mid + 1;
3332                 }
3333               if (hi > 0 &&
3334                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3335                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3336             }
3337         });
3338       i++;
3339       ir++;
3340     }
3341   while (i < count)
3342     glyphs[i++] = kCGFontIndexInvalid;
3343   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3344   dispatch_release (group);
3347 static int
3348 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3350   CFDataRef uvs_table;
3351   CTCharacterCollection uvs_collection;
3352   int i, n = 0;
3354   block_input ();
3355   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3357   if (uvs_table)
3358     {
3359       UTF32Char selectors[256];
3360       CGGlyph glyphs[256];
3362       for (i = 0; i < 16; i++)
3363         selectors[i] = 0xFE00 + i;
3364       for (; i < 256; i++)
3365         selectors[i] = 0xE0100 + (i - 16);
3366       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3367       for (i = 0; i < 256; i++)
3368         {
3369           CGGlyph glyph = glyphs[i];
3371           if (uvs_collection != kCTCharacterCollectionIdentityMapping
3372               && glyph != kCGFontIndexInvalid)
3373             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3374           if (glyph == kCGFontIndexInvalid)
3375             variations[i] = 0;
3376           else
3377             {
3378               variations[i] = (glyph ? glyph
3379                                : macfont_get_glyph_for_character (font, c));
3380               n++;
3381             }
3382         }
3383     }
3384   unblock_input ();
3386   return n;
3389 static const char *const macfont_booleans[] = {
3390   ":antialias",
3391   ":minspace",
3392   NULL,
3395 static const char *const macfont_non_booleans[] = {
3396   ":lang",
3397   ":script",
3398   ":destination",
3399   NULL,
3402 static void
3403 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3405   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3408 static Boolean
3409 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3410                                         CFArrayRef languages)
3412   Boolean result = true;
3413   CFArrayRef desc_languages =
3414     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3416   if (desc_languages == NULL)
3417     result = false;
3418   else
3419     {
3420       CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3421       CFIndex i, languages_count = CFArrayGetCount (languages);
3423       for (i = 0; i < languages_count; i++)
3424         {
3425           CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3427           if (!CFArrayContainsValue (desc_languages, range, language)
3428               /* PingFang SC contains "zh" and "zh-Hant" as covered
3429                  languages, but does not contain "zh-Hans".  */
3430               && !(CFEqual (language, CFSTR ("zh-Hans"))
3431                    && CFArrayContainsValue (desc_languages, range,
3432                                             CFSTR ("zh"))))
3433             {
3434               result = false;
3435               break;
3436             }
3437         }
3438       CFRelease (desc_languages);
3439     }
3441   return result;
3444 static CFStringRef
3445 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3447   CFStringRef result = NULL;
3448   CFStringRef charset_string =
3449     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3451   if (charset_string && CFStringGetLength (charset_string) > 0)
3452     {
3453       CFStringRef keys[] = {
3454 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3455         kCTLanguageAttributeName
3456 #else
3457         CFSTR ("NSLanguage")
3458 #endif
3459       };
3460       CFTypeRef values[] = {NULL};
3461       CFIndex num_values = 0;
3462       CFArrayRef languages
3463         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3465       if (languages && CFArrayGetCount (languages) > 0)
3466         {
3467           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3468             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3469           else
3470             {
3471               CFCharacterSetRef charset =
3472                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3474               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3475             }
3476         }
3477       if (result == NULL)
3478         {
3479           CFAttributedStringRef attr_string = NULL;
3480           CTLineRef ctline = NULL;
3481           CFDictionaryRef attrs
3482             = CFDictionaryCreate (NULL, (const void **) keys,
3483                                   (const void **) values, num_values,
3484                                   &kCFTypeDictionaryKeyCallBacks,
3485                                   &kCFTypeDictionaryValueCallBacks);
3487           if (attrs)
3488             {
3489               attr_string = CFAttributedStringCreate (NULL, charset_string,
3490                                                       attrs);
3491               CFRelease (attrs);
3492             }
3493           if (attr_string)
3494             {
3495               ctline = CTLineCreateWithAttributedString (attr_string);
3496               CFRelease (attr_string);
3497             }
3498           if (ctline)
3499             {
3500               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3501               CFIndex i, nruns = CFArrayGetCount (runs);
3502               CTFontRef font;
3504               for (i = 0; i < nruns; i++)
3505                 {
3506                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3507                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3508                   CTFontRef font_in_run;
3510                   if (attributes == NULL)
3511                     break;
3512                   font_in_run =
3513                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3514                   if (font_in_run == NULL)
3515                     break;
3516                   if (i == 0)
3517                     font = font_in_run;
3518                   else if (!mac_font_equal_in_postscript_name (font,
3519                                                                font_in_run))
3520                     break;
3521                 }
3522               if (nruns > 0 && i == nruns)
3523                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3524               CFRelease (ctline);
3525             }
3526         }
3527     }
3529   return result;
3532 static inline double
3533 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3535   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3536                                      &glyph, NULL, 1);
3539 static inline CGRect
3540 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3542   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3543                                           &glyph, NULL, 1);
3546 static CFArrayRef
3547 mac_font_create_available_families (void)
3549   CFMutableArrayRef families = NULL;
3550   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3552   if (orig_families)
3553     {
3554       CFIndex i, count = CFArrayGetCount (orig_families);
3556       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3557       if (families)
3558         for (i = 0; i < count; i++)
3559           {
3560             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3562             if (!CFStringHasPrefix (family, CFSTR ("."))
3563                 && (CTFontManagerCompareFontFamilyNames (family,
3564                                                          CFSTR ("LastResort"),
3565                                                          NULL)
3566                     != kCFCompareEqualTo))
3567               CFArrayAppendValue (families, family);
3568           }
3569       CFRelease (orig_families);
3570     }
3572   return families;
3575 static Boolean
3576 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3578   Boolean result;
3579   CFStringRef name1, name2;
3581   if (font1 == font2)
3582     return true;
3584   result = false;
3585   name1 = CTFontCopyPostScriptName (font1);
3586   if (name1)
3587     {
3588       name2 = CTFontCopyPostScriptName (font2);
3589       if (name2)
3590         {
3591           result = CFEqual (name1, name2);
3592           CFRelease (name2);
3593         }
3594       CFRelease (name1);
3595     }
3597   return result;
3600 static CTLineRef
3601 mac_font_create_line_with_string_and_font (CFStringRef string,
3602                                            CTFontRef macfont)
3604   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3605   CFTypeRef values[] = {NULL, NULL};
3606   CFDictionaryRef attributes = NULL;
3607   CFAttributedStringRef attr_string = NULL;
3608   CTLineRef ctline = NULL;
3609   float float_zero = 0.0f;
3611   values[0] = macfont;
3612   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3613   if (values[1])
3614     {
3615       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3616                                        (const void **) values,
3617                                        ARRAYELTS (keys),
3618                                        &kCFTypeDictionaryKeyCallBacks,
3619                                        &kCFTypeDictionaryValueCallBacks);
3620       CFRelease (values[1]);
3621     }
3622   if (attributes)
3623     {
3624       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3625       CFRelease (attributes);
3626     }
3627   if (attr_string)
3628     {
3629       ctline = CTLineCreateWithAttributedString (attr_string);
3630       CFRelease (attr_string);
3631     }
3632   if (ctline)
3633     {
3634       /* Abandon if ctline contains some fonts other than the
3635          specified one.  */
3636       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3637       CFIndex i, nruns = CFArrayGetCount (runs);
3639       for (i = 0; i < nruns; i++)
3640         {
3641           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3642           CFDictionaryRef attributes = CTRunGetAttributes (run);
3643           CTFontRef font_in_run;
3645           if (attributes == NULL)
3646             break;
3647           font_in_run =
3648             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3649           if (font_in_run == NULL)
3650             break;
3651           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3652             break;
3653         }
3654       if (i < nruns)
3655         {
3656           CFRelease (ctline);
3657           ctline = NULL;
3658         }
3659     }
3661   return ctline;
3664 static CFIndex
3665 mac_font_shape (CTFontRef font, CFStringRef string,
3666                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3668   CFIndex used, result = 0;
3669   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3671   if (ctline == NULL)
3672     return 0;
3674   used = CTLineGetGlyphCount (ctline);
3675   if (used <= glyph_len)
3676     {
3677       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3678       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3679       CGFloat total_advance = 0;
3680       CFIndex total_glyph_count = 0;
3682       for (k = 0; k < ctrun_count; k++)
3683         {
3684           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3685           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3686           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3687           CFRange string_range, comp_range, range;
3688           CFIndex *permutation;
3690           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3691             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3692           else
3693             permutation = NULL;
3695 #define RIGHT_TO_LEFT_P permutation
3697           /* Now the `comp_range' member of struct mac_glyph_layout is
3698              temporarily used as a work area such that:
3699              glbuf[i].comp_range.location =
3700              min {compRange[i + 1].location, ...,
3701                      compRange[glyph_count - 1].location,
3702                      maxRange (stringRangeForCTRun)}
3703              glbuf[i].comp_range.length = maxRange (compRange[i])
3704              where compRange[i] is the range of composed characters
3705              containing i-th glyph.  */
3706           string_range = CTRunGetStringRange (ctrun);
3707           min_location = string_range.location + string_range.length;
3708           for (i = 0; i < glyph_count; i++)
3709             {
3710               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3711               CFIndex glyph_index;
3712               CFRange rng;
3714               if (!RIGHT_TO_LEFT_P)
3715                 glyph_index = glyph_count - i - 1;
3716               else
3717                 glyph_index = i;
3718               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3719                                      &gl->string_index);
3720               rng =
3721                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3722                                                              gl->string_index);
3723               gl->comp_range.location = min_location;
3724               gl->comp_range.length = rng.location + rng.length;
3725               if (rng.location < min_location)
3726                 min_location = rng.location;
3727             }
3729           /* Fill the `comp_range' member of struct mac_glyph_layout,
3730              and setup a permutation for right-to-left text.  */
3731           comp_range = CFRangeMake (string_range.location, 0);
3732           range = CFRangeMake (0, 0);
3733           while (1)
3734             {
3735               struct mac_glyph_layout *gl =
3736                 glbuf + range.location + range.length;
3738               if (gl->comp_range.length
3739                   > comp_range.location + comp_range.length)
3740                 comp_range.length = gl->comp_range.length - comp_range.location;
3741               min_location = gl->comp_range.location;
3742               range.length++;
3744               if (min_location >= comp_range.location + comp_range.length)
3745                 {
3746                   comp_range.length = min_location - comp_range.location;
3747                   for (i = 0; i < range.length; i++)
3748                     {
3749                       glbuf[range.location + i].comp_range = comp_range;
3750                       if (RIGHT_TO_LEFT_P)
3751                         permutation[range.location + i] =
3752                           range.location + range.length - i - 1;
3753                     }
3755                   comp_range = CFRangeMake (min_location, 0);
3756                   range.location += range.length;
3757                   range.length = 0;
3758                   if (range.location == glyph_count)
3759                     break;
3760                 }
3761             }
3763           /* Then fill the remaining members.  */
3764           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3765                range.location++)
3766             {
3767               struct mac_glyph_layout *gl;
3768               CGPoint position;
3770               if (!RIGHT_TO_LEFT_P)
3771                 gl = glbuf + range.location;
3772               else
3773                 {
3774                   CFIndex src, dest;
3776                   src = glyph_count - 1 - range.location;
3777                   dest = permutation[src];
3778                   gl = glbuf + dest;
3779                   if (src < dest)
3780                     {
3781                       CFIndex tmp = gl->string_index;
3783                       gl->string_index = glbuf[src].string_index;
3784                       glbuf[src].string_index = tmp;
3785                     }
3786                 }
3787               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3789               CTRunGetPositions (ctrun, range, &position);
3790               gl->advance_delta = position.x - total_advance;
3791               gl->baseline_delta = position.y;
3792               gl->advance = (gl->advance_delta
3793                              + CTRunGetTypographicBounds (ctrun, range,
3794                                                           NULL, NULL, NULL));
3795               total_advance += gl->advance;
3796             }
3798           if (RIGHT_TO_LEFT_P)
3799             xfree (permutation);
3801 #undef RIGHT_TO_LEFT_P
3803           total_glyph_count += glyph_count;
3804         }
3806       result = used;
3807     }
3808   CFRelease (ctline);
3810   return result;
3813 /* The function below seems to cause a memory leak for the CFString
3814    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3815    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3816 #if USE_CT_GLYPH_INFO
3817 static CGGlyph
3818 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3819                               CGFontIndex cid)
3821   CGGlyph result = kCGFontIndexInvalid;
3822   UniChar characters[] = {0xfffd};
3823   CFStringRef string;
3824   CFAttributedStringRef attr_string = NULL;
3825   CTLineRef ctline = NULL;
3827   string = CFStringCreateWithCharacters (NULL, characters,
3828                                          ARRAYELTS (characters));
3830   if (string)
3831     {
3832       CTGlyphInfoRef glyph_info =
3833         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3834       CFDictionaryRef attributes = NULL;
3836       if (glyph_info)
3837         {
3838           CFStringRef keys[] = {kCTFontAttributeName,
3839                                 kCTGlyphInfoAttributeName};
3840           CFTypeRef values[] = {font, glyph_info};
3842           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3843                                            (const void **) values,
3844                                            ARRAYELTS (keys),
3845                                            &kCFTypeDictionaryKeyCallBacks,
3846                                            &kCFTypeDictionaryValueCallBacks);
3847           CFRelease (glyph_info);
3848         }
3849       if (attributes)
3850         {
3851           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3852           CFRelease (attributes);
3853         }
3854       CFRelease (string);
3855     }
3856   if (attr_string)
3857     {
3858       ctline = CTLineCreateWithAttributedString (attr_string);
3859       CFRelease (attr_string);
3860     }
3861   if (ctline)
3862     {
3863       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3865       if (CFArrayGetCount (runs) > 0)
3866         {
3867           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3868           CFDictionaryRef attributes = CTRunGetAttributes (run);
3870           if (attributes)
3871             {
3872               CTFontRef font_in_run =
3873                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3875               if (font_in_run
3876                   && mac_font_equal_in_postscript_name (font_in_run, font))
3877                 {
3878                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3879                   if (result >= CTFontGetGlyphCount (font))
3880                     result = kCGFontIndexInvalid;
3881                 }
3882             }
3883         }
3884       CFRelease (ctline);
3885     }
3887   return result;
3889 #endif
3891 static CFArrayRef
3892 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3894   CFArrayRef result = NULL;
3896 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3897 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3898   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3899 #endif
3900     {
3901       CTFontRef user_font =
3902         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3904       if (user_font)
3905         {
3906           CFArrayRef languages =
3907             CFArrayCreate (NULL, (const void **) &language, 1,
3908                            &kCFTypeArrayCallBacks);
3910           if (languages)
3911             {
3912               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3913                                                                  languages);
3914               CFRelease (languages);
3915             }
3916           CFRelease (user_font);
3917         }
3918     }
3919 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3920   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3921 #endif
3922 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3923 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3924     {
3925       CFIndex i;
3927       for (i = 0; macfont_language_default_font_names[i].language; i++)
3928         {
3929           if (CFEqual (macfont_language_default_font_names[i].language,
3930                        language))
3931             {
3932               CFMutableArrayRef descriptors =
3933                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3935               if (descriptors)
3936                 {
3937                   CFIndex j;
3939                   for (j = 0;
3940                        macfont_language_default_font_names[i].font_names[j];
3941                        j++)
3942                     {
3943                       CFDictionaryRef attributes =
3944                         CFDictionaryCreate (NULL,
3945                                             ((const void **)
3946                                              &kCTFontNameAttribute),
3947                                             ((const void **)
3948                                              &macfont_language_default_font_names[i].font_names[j]),
3949                                             1, &kCFTypeDictionaryKeyCallBacks,
3950                                             &kCFTypeDictionaryValueCallBacks);
3952                       if (attributes)
3953                         {
3954                           CTFontDescriptorRef pat_desc =
3955                             CTFontDescriptorCreateWithAttributes (attributes);
3957                           if (pat_desc)
3958                             {
3959                               CTFontDescriptorRef descriptor =
3960                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3962                               if (descriptor)
3963                                 {
3964                                   CFArrayAppendValue (descriptors, descriptor);
3965                                   CFRelease (descriptor);
3966                                 }
3967                               CFRelease (pat_desc);
3968                             }
3969                           CFRelease (attributes);
3970                         }
3971                     }
3972                   result = descriptors;
3973                 }
3974               break;
3975             }
3976         }
3977     }
3978 #endif
3980   return result;
3983 static CFStringRef
3984 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3985                                                       CFArrayRef languages)
3987   CFStringRef result = NULL;
3988   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3989   CFArrayRef descriptors =
3990     mac_font_copy_default_descriptors_for_language (language);
3992   if (descriptors)
3993     {
3994       CFIndex i, count = CFArrayGetCount (descriptors);
3996       for (i = 0; i < count; i++)
3997         {
3998           CTFontDescriptorRef descriptor =
3999             CFArrayGetValueAtIndex (descriptors, i);
4001           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4002                                                         Qnil, languages))
4003             {
4004               CFStringRef family =
4005                 CTFontDescriptorCopyAttribute (descriptor,
4006                                                kCTFontFamilyNameAttribute);
4007               if (family)
4008                 {
4009                   if (!CFStringHasPrefix (family, CFSTR ("."))
4010                       && !CFEqual (family, CFSTR ("LastResort")))
4011                     {
4012                       result = family;
4013                       break;
4014                     }
4015                   else
4016                     CFRelease (family);
4017                 }
4018             }
4019         }
4020       CFRelease (descriptors);
4021     }
4023   return result;
4026 void *
4027 macfont_get_nsctfont (struct font *font)
4029   struct macfont_info *macfont_info = (struct macfont_info *) font;
4030   CTFontRef macfont = macfont_info->macfont;
4032   return (void *) macfont;
4035 void
4036 mac_register_font_driver (struct frame *f)
4038   register_font_driver (&macfont_driver, f);
4042 void
4043 syms_of_macfont (void)
4045   /* Core Text, for Mac OS X.  */
4046   DEFSYM (Qmac_ct, "mac-ct");
4047   macfont_driver.type = Qmac_ct;
4048   register_font_driver (&macfont_driver, NULL);
4050   /* The font property key specifying the font design destination.  The
4051      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4052      text.  (See the documentation of X Logical Font Description
4053      Conventions.)  In the Mac font driver, 1 means the screen font is
4054      used for calculating some glyph metrics.  You can see the
4055      difference with Monaco 8pt or 9pt, for example.  */
4056   DEFSYM (QCdestination, ":destination");
4058   /* The boolean-valued font property key specifying the use of leading.  */
4059   DEFSYM (QCminspace, ":minspace");
4061   macfont_family_cache = Qnil;
4062   staticpro (&macfont_family_cache);