After delete, record point location in undo.
[emacs.git] / src / macfont.m
blobfae284fad892e11ae6a8847a2aa47568634db40b
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2015 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
22 #include <config.h>
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "frame.h"
27 #include "blockinput.h"
28 #include "character.h"
29 #include "charset.h"
30 #include "composite.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "termchar.h"
34 #include "nsgui.h"
35 #include "nsterm.h"
36 #include "macfont.h"
37 #include "macuvs.h"
39 #include <libkern/OSByteOrder.h>
41 static struct font_driver macfont_driver;
43 static double mac_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 || percent_val == 56)
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           if (percent_val == -40)
790             {
791               /* Workaround for crash when displaying Oriya characters
792                  with Arial Unicode MS on OS X 10.11.  */
793               if (weight == 5)
794                 val = 0;
795             }
796           else                  /* percent_val == 56 */
797             {
798               if (weight == 9)
799                 /* Adjustment for HiraginoSans-W7 on OS X 10.11.  */
800                 val = 0.4;
801             }
802           CFRelease (font);
803         }
804     }
806   return val;
809 static void
810 macfont_store_descriptor_attributes (CTFontDescriptorRef desc,
811                                      Lisp_Object spec_or_entity)
813   CFStringRef str;
814   CFDictionaryRef dict;
815   CFNumberRef num;
816   CGFloat floatval;
818   str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
819   if (str)
820     {
821       ASET (spec_or_entity, FONT_FAMILY_INDEX,
822             macfont_intern_prop_cfstring (str));
823       CFRelease (str);
824     }
825   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
826   if (dict)
827     {
828       struct {
829         enum font_property_index index;
830         CFStringRef trait;
831         CGPoint points[6];
832         CGFloat (*adjust_func) (CTFontDescriptorRef, CGFloat);
833       } numeric_traits[] =
834           {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
835             {{-0.4, 50},        /* light */
836              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
837              {0, 100},          /* normal */
838              {0.24, 140},       /* (semi-bold + normal) / 2 */
839              {0.4, 200},        /* bold */
840              {CGFLOAT_MAX, CGFLOAT_MAX}},
841             mac_font_descriptor_get_adjusted_weight},
842            {FONT_SLANT_INDEX, kCTFontSlantTrait,
843             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL},
844            {FONT_WIDTH_INDEX, kCTFontWidthTrait,
845             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL}};
846       int i;
848       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
849         {
850           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
851           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
852             {
853               CGPoint *point = numeric_traits[i].points;
855               if (numeric_traits[i].adjust_func)
856                 floatval = (*numeric_traits[i].adjust_func) (desc, floatval);
857               while (point->x < floatval)
858                 point++;
859               if (point == numeric_traits[i].points)
860                 point++;
861               else if (point->x == CGFLOAT_MAX)
862                 point--;
863               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
864                                            * ((point->y - (point - 1)->y)
865                                               / (point->x - (point - 1)->x)));
866               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
867                               make_number (lround (floatval)));
868             }
869         }
871       num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
872       if (num)
873         {
874           CTFontSymbolicTraits sym_traits;
875           int spacing;
877           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
878           spacing = (sym_traits & kCTFontTraitMonoSpace
879                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
880           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
881         }
883       CFRelease (dict);
884     }
885   num = CTFontDescriptorCopyAttribute (desc, kCTFontSizeAttribute);
886   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
887     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
888   else
889     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
890   if (num)
891     CFRelease (num);
894 static Lisp_Object
895 macfont_descriptor_entity (CTFontDescriptorRef desc, Lisp_Object extra,
896                            CTFontSymbolicTraits synth_sym_traits)
898   Lisp_Object entity;
899   CFDictionaryRef dict;
900   CTFontSymbolicTraits sym_traits = 0;
901   CFStringRef name;
903   entity = font_make_entity ();
905   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
906   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
908   macfont_store_descriptor_attributes (desc, entity);
910   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
911   if (dict)
912     {
913       CFNumberRef num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
915       if (num)
916         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
917       CFRelease (dict);
918     }
919   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
920     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
921   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
922   name = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
923   font_put_extra (entity, QCfont_entity,
924                   make_save_ptr_int ((void *) name, sym_traits));
925   if (synth_sym_traits & kCTFontTraitItalic)
926     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
927                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
928   if (synth_sym_traits & kCTFontTraitBold)
929     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
930                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
931   if (synth_sym_traits & kCTFontTraitMonoSpace)
932     ASET (entity, FONT_SPACING_INDEX,
933           make_number (FONT_SPACING_SYNTHETIC_MONO));
935   return entity;
938 /* Cache for font family name symbols vs CFStrings.  A value of nil
939 means the cache has been invalidated.  Otherwise the value is a Lisp
940 hash table whose keys are symbols and the value for a key is either
941 nil (no corresponding family name) or a Lisp save value wrapping the
942 corresponding family name in CFString.  */
944 static Lisp_Object macfont_family_cache;
946 static void
947 macfont_invalidate_family_cache (void)
949   if (HASH_TABLE_P (macfont_family_cache))
950     {
951       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
952       ptrdiff_t i, size = HASH_TABLE_SIZE (h);
954       for (i = 0; i < size; ++i)
955         if (!NILP (HASH_HASH (h, i)))
956           {
957             Lisp_Object value = HASH_VALUE (h, i);
959             if (SAVE_VALUEP (value))
960               CFRelease (XSAVE_POINTER (value, 0));
961           }
962       macfont_family_cache = Qnil;
963     }
966 static bool
967 macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
969   if (HASH_TABLE_P (macfont_family_cache))
970     {
971       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
972       ptrdiff_t i = hash_lookup (h, symbol, NULL);
974       if (i >= 0)
975         {
976           Lisp_Object value = HASH_VALUE (h, i);
978           *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
980           return true;
981         }
982     }
984   return false;
987 static void
988 macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
990   struct Lisp_Hash_Table *h;
991   ptrdiff_t i;
992   EMACS_UINT hash;
993   Lisp_Object value;
995   if (!HASH_TABLE_P (macfont_family_cache))
996     macfont_family_cache = CALLN (Fmake_hash_table, QCtest, Qeq);
998   h = XHASH_TABLE (macfont_family_cache);
999   i = hash_lookup (h, symbol, &hash);
1000   value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
1001   if (i >= 0)
1002     {
1003       Lisp_Object old_value = HASH_VALUE (h, i);
1005       if (SAVE_VALUEP (old_value))
1006         CFRelease (XSAVE_POINTER (old_value, 0));
1007       set_hash_value_slot (h, i, value);
1008     }
1009   else
1010     hash_put (h, symbol, value, hash);
1013 /* Cache of all the available font family names except "LastResort"
1014 and those start with ".".  NULL means the cache has been invalidated.
1015 Otherwise, the value is CFArray of CFStrings and the elements are
1016 sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
1017 OS X 10.6 and later).  */
1019 static CFArrayRef macfont_available_families_cache = NULL;
1021 static void
1022 macfont_invalidate_available_families_cache (void)
1024   if (macfont_available_families_cache)
1025     {
1026       CFRelease (macfont_available_families_cache);
1027       macfont_available_families_cache = NULL;
1028     }
1031 static void
1032 macfont_handle_font_change_notification (CFNotificationCenterRef center,
1033                                          void *observer,
1034                                          CFStringRef name, const void *object,
1035                                          CFDictionaryRef userInfo)
1037   macfont_invalidate_family_cache ();
1038   macfont_invalidate_available_families_cache ();
1041 static void
1042 macfont_init_font_change_handler (void)
1044   static bool initialized = false;
1046   if (initialized)
1047     return;
1049   initialized = true;
1050   CFNotificationCenterAddObserver
1051     (CFNotificationCenterGetLocalCenter (), NULL,
1052      macfont_handle_font_change_notification,
1053      kCTFontManagerRegisteredFontsChangedNotification,
1054      NULL, CFNotificationSuspensionBehaviorCoalesce);
1057 static CFArrayRef
1058 macfont_copy_available_families_cache (void)
1060   macfont_init_font_change_handler ();
1062   if (macfont_available_families_cache == NULL)
1063     macfont_available_families_cache = mac_font_create_available_families ();
1065   return (macfont_available_families_cache
1066           ? CFRetain (macfont_available_families_cache) : NULL);
1069 static CFStringRef
1070 macfont_create_family_with_symbol (Lisp_Object symbol)
1072   CFStringRef result = NULL, family_name;
1073   CFDictionaryRef attributes = NULL;
1074   CTFontDescriptorRef pat_desc = NULL;
1076   if (macfont_get_family_cache_if_present (symbol, &result))
1077     return result ? CFRetain (result) : NULL;
1079   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1080   if (family_name)
1081     {
1082       attributes =
1083         CFDictionaryCreate (NULL,
1084                             (const void **) &kCTFontFamilyNameAttribute,
1085                             (const void **) &family_name, 1,
1086                             &kCFTypeDictionaryKeyCallBacks,
1087                             &kCFTypeDictionaryValueCallBacks);
1088       CFRelease (family_name);
1089     }
1090   if (attributes)
1091     {
1092       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
1093       CFRelease (attributes);
1094     }
1095   if (pat_desc)
1096     {
1097       CTFontDescriptorRef desc =
1098         CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
1100       if (desc)
1101         {
1102           result =
1103             CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
1104           CFRelease (desc);
1105         }
1106       macfont_set_family_cache (symbol, result);
1107       CFRelease (pat_desc);
1108     }
1110   return result;
1113 #define WIDTH_FRAC_BITS         (4)
1114 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1116 struct macfont_metrics
1118   unsigned char lbearing_low, rbearing_low;
1119   signed lbearing_high : 4, rbearing_high : 4;
1120   unsigned char ascent_low, descent_low;
1121   signed ascent_high : 4, descent_high : 4;
1123   /* These two members are used for fixed-point representation of
1124      glyph width.  The `width_int' member is an integer that is
1125      closest to the width.  The `width_frac' member is the fractional
1126      adjustment representing a value in [-.5, .5], multiplied by
1127      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1128      the advance delta for centering instead of the glyph width.  */
1129   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1132 #define METRICS_VALUE(metrics, member)                          \
1133   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1134 #define METRICS_SET_VALUE(metrics, member, value)                   \
1135   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
1136     (metrics)->member##_high = tmp >> 8;} while (0)
1138 enum metrics_status
1140   METRICS_INVALID = -1,    /* metrics entry is invalid */
1141   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1144 #define METRICS_STATUS(metrics)                                         \
1145   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1146 #define METRICS_SET_STATUS(metrics, status)                     \
1147   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1148     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1150 #define METRICS_NCOLS_PER_ROW   (128)
1151 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1152 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1154 static int
1155 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1156                        struct font_metrics *metrics, CGFloat *advance_delta,
1157                        int force_integral_p)
1159   struct macfont_info *macfont_info = (struct macfont_info *) font;
1160   CTFontRef macfont = macfont_info->macfont;
1161   int row, col;
1162   struct macfont_metrics *cache;
1163   int width;
1165   row = glyph / METRICS_NCOLS_PER_ROW;
1166   col = glyph % METRICS_NCOLS_PER_ROW;
1167   if (row >= macfont_info->metrics_nrows)
1168     {
1169       macfont_info->metrics =
1170         xrealloc (macfont_info->metrics,
1171                   sizeof (struct macfont_metrics *) * (row + 1));
1172       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1173               (sizeof (struct macfont_metrics *)
1174                * (row + 1 - macfont_info->metrics_nrows)));
1175       macfont_info->metrics_nrows = row + 1;
1176     }
1177   if (macfont_info->metrics[row] == NULL)
1178     {
1179       struct macfont_metrics *new;
1180       int i;
1182       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1183       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1184         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1185       macfont_info->metrics[row] = new;
1186     }
1187   cache = macfont_info->metrics[row] + col;
1189   if (METRICS_STATUS (cache) == METRICS_INVALID)
1190     {
1191       CGFloat fwidth;
1193       if (macfont_info->screen_font)
1194         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1195       else
1196         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1198       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1199          advance delta value.  */
1200       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1201         fwidth = (font->pixel_size - fwidth) / 2;
1202       cache->width_int = lround (fwidth);
1203       cache->width_frac = lround ((fwidth - cache->width_int)
1204                                   * WIDTH_FRAC_SCALE);
1205       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1206     }
1207   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1208     width = font->pixel_size;
1209   else
1210     width = cache->width_int;
1212   if (metrics)
1213     {
1214       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1215         {
1216           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1218           if (macfont_info->synthetic_italic_p)
1219             {
1220               /* We assume the members a, b, c, and d in
1221                  synthetic_italic_atfm are non-negative.  */
1222               bounds.origin =
1223                 CGPointApplyAffineTransform (bounds.origin,
1224                                              synthetic_italic_atfm);
1225               bounds.size =
1226                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1227             }
1228           if (macfont_info->synthetic_bold_p && ! force_integral_p)
1229             {
1230               CGFloat d = - synthetic_bold_factor * CTFontGetSize (macfont) / 2;
1232               bounds = CGRectInset (bounds, d, d);
1233             }
1234           switch (macfont_info->spacing)
1235             {
1236             case MACFONT_SPACING_PROPORTIONAL:
1237               bounds.origin.x += - (cache->width_frac
1238                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1239               break;
1240             case MACFONT_SPACING_MONO:
1241               break;
1242             case MACFONT_SPACING_SYNTHETIC_MONO:
1243               bounds.origin.x += (cache->width_int
1244                                   + (cache->width_frac
1245                                      / (CGFloat) WIDTH_FRAC_SCALE));
1246               break;
1247             }
1248           if (bounds.size.width > 0)
1249             {
1250               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1251               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1252                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1253             }
1254           bounds = CGRectIntegral (bounds);
1255           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1256           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1257           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1258           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1259         }
1260       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1261       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1262       metrics->width = width;
1263       metrics->ascent = METRICS_VALUE (cache, ascent);
1264       metrics->descent = METRICS_VALUE (cache, descent);
1265     }
1267   if (advance_delta)
1268     {
1269       switch (macfont_info->spacing)
1270         {
1271         case MACFONT_SPACING_PROPORTIONAL:
1272           *advance_delta = (force_integral_p ? 0
1273                             : - (cache->width_frac
1274                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1275           break;
1276         case MACFONT_SPACING_MONO:
1277           *advance_delta = 0;
1278           break;
1279         case MACFONT_SPACING_SYNTHETIC_MONO:
1280           *advance_delta = (force_integral_p ? cache->width_int
1281                             : (cache->width_int
1282                                + (cache->width_frac
1283                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1284           break;
1285         }
1286     }
1288   return width;
1291 static CFMutableDictionaryRef macfont_cache_dictionary;
1293 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1294    equal to the number of rows that are invalid as BMP (i.e., from
1295    U+D800 to U+DFFF).  */
1296 #define ROW_PERM_OFFSET (8)
1298 /* The number of glyphs that can be stored in a value for a single
1299    entry of CFDictionary.  */
1300 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1302 struct macfont_cache
1304   int reference_count;
1305   CFCharacterSetRef cf_charset;
1306   struct {
1307     /* The cached glyph for a BMP character c is stored in
1308        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1309        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1310     unsigned char row_nkeys_or_perm[256];
1311     CGGlyph **matrix;
1313     /* Number of rows for which the BMP cache is allocated so far.
1314        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1315     int nrows;
1317     /* The cached glyph for a character c is stored as the (c %
1318        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1319        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1320        not stored here if row_nkeys_or_perm[c / 256] >=
1321        ROW_PERM_OFFSET.  */
1322     CFMutableDictionaryRef dictionary;
1323   } glyph;
1325   struct {
1326     /* UVS (Unicode Variation Sequence) subtable data, which is of
1327        type CFDataRef if available.  NULL means it is not initialized
1328        yet.  kCFNull means the subtable is not found and there is no
1329        suitable fallback table for this font.  */
1330     CFTypeRef table;
1332     /* Character collection specifying the destination of the mapping
1333        provided by `table' above.  If `table' is obtained from the UVS
1334        subtable in the font cmap table, then the value of this member
1335        should be kCTCharacterCollectionIdentityMapping.  */
1336     CTCharacterCollection collection;
1337   } uvs;
1340 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1341 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1342 static void macfont_release_cache (struct macfont_cache *);
1343 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1344 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1345 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1346 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1347                                           CTCharacterCollection, CGFontIndex);
1348 static CFDataRef macfont_get_uvs_table (struct font *, CTCharacterCollection *);
1350 static struct macfont_cache *
1351 macfont_lookup_cache (CFStringRef key)
1353   struct macfont_cache *cache;
1355   if (macfont_cache_dictionary == NULL)
1356     {
1357       macfont_cache_dictionary =
1358         CFDictionaryCreateMutable (NULL, 0,
1359                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1360       cache = NULL;
1361     }
1362   else
1363     cache = ((struct macfont_cache *)
1364              CFDictionaryGetValue (macfont_cache_dictionary, key));
1366   if (cache == NULL)
1367     {
1368       CTFontRef macfont = CTFontCreateWithName (key, 0, NULL);
1370       if (macfont)
1371         {
1372           cache = xzalloc (sizeof (struct macfont_cache));
1373           /* Treat the LastResort font as if it contained glyphs for
1374              all characters.  This may look too rough, but neither
1375              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1376              for this font is correct for non-BMP characters on Mac OS
1377              X 10.5, anyway.  */
1378           if (CFEqual (key, CFSTR ("LastResort")))
1379             {
1380               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1382               cache->cf_charset =
1383                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1384             }
1385           if (cache->cf_charset == NULL)
1386             cache->cf_charset = CTFontCopyCharacterSet (macfont);
1387           CFDictionaryAddValue (macfont_cache_dictionary, key,
1388                                 (const void *) cache);
1389           CFRelease (macfont);
1390         }
1391     }
1393   return cache;
1396 static struct macfont_cache *
1397 macfont_retain_cache (struct macfont_cache *cache)
1399   cache->reference_count++;
1401   return cache;
1404 static void
1405 macfont_release_cache (struct macfont_cache *cache)
1407   if (--cache->reference_count == 0)
1408     {
1409       int i;
1411       for (i = 0; i < cache->glyph.nrows; i++)
1412         xfree (cache->glyph.matrix[i]);
1413       xfree (cache->glyph.matrix);
1414       if (cache->glyph.dictionary)
1415         CFRelease (cache->glyph.dictionary);
1416       memset (&cache->glyph, 0, sizeof (cache->glyph));
1417       if (cache->uvs.table)
1418         CFRelease (cache->uvs.table);
1419       memset (&cache->uvs, 0, sizeof (cache->uvs));
1420     }
1423 static CFCharacterSetRef
1424 macfont_get_cf_charset (struct font *font)
1426   struct macfont_info *macfont_info = (struct macfont_info *) font;
1428   return macfont_info->cache->cf_charset;
1431 static CFCharacterSetRef
1432 macfont_get_cf_charset_for_name (CFStringRef name)
1434   struct macfont_cache *cache = macfont_lookup_cache (name);
1436   return cache->cf_charset;
1439 static CGGlyph
1440 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1442   struct macfont_info *macfont_info = (struct macfont_info *) font;
1443   CTFontRef macfont = macfont_info->macfont;
1444   struct macfont_cache *cache = macfont_info->cache;
1446   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1447     {
1448       int row = c / 256;
1449       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1451       if (nkeys_or_perm < ROW_PERM_OFFSET)
1452         {
1453           UniChar unichars[256], ch;
1454           CGGlyph *glyphs;
1455           int i, len;
1456           int nrows;
1457           dispatch_queue_t queue;
1458           dispatch_group_t group = NULL;
1460           if (row != 0)
1461             {
1462               CFMutableDictionaryRef dictionary;
1463               uintptr_t key, value;
1464               int nshifts;
1465               CGGlyph glyph;
1467               if (cache->glyph.dictionary == NULL)
1468                 cache->glyph.dictionary =
1469                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1470               dictionary = cache->glyph.dictionary;
1471               key = c / NGLYPHS_IN_VALUE;
1472               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1473               value = ((uintptr_t)
1474                        CFDictionaryGetValue (dictionary, (const void *) key));
1475               glyph = (value >> nshifts);
1476               if (glyph)
1477                 return glyph;
1479               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1480                 {
1481                   ch = c;
1482                   if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1483                       || glyph == 0)
1484                     glyph = kCGFontIndexInvalid;
1486                   if (value == 0)
1487                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1488                   value |= ((uintptr_t) glyph << nshifts);
1489                   CFDictionarySetValue (dictionary, (const void *) key,
1490                                         (const void *) value);
1492                   return glyph;
1493                 }
1495               queue =
1496                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1497               group = dispatch_group_create ();
1498               dispatch_group_async (group, queue, ^{
1499                   int nkeys;
1500                   uintptr_t key;
1501                   nkeys = nkeys_or_perm;
1502                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1503                     if (CFDictionaryContainsKey (dictionary,
1504                                                  (const void *) key))
1505                       {
1506                         CFDictionaryRemoveValue (dictionary,
1507                                                  (const void *) key);
1508                         if (--nkeys == 0)
1509                           break;
1510                       }
1511                 });
1512             }
1514           len = 0;
1515           for (i = 0; i < 256; i++)
1516             {
1517               ch = row * 256 + i;
1518               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1519                 unichars[len++] = ch;
1520             }
1522           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1523           if (len > 0)
1524             {
1525               CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1526               while (i > len)
1527                 {
1528                   int next = unichars[len - 1] % 256;
1530                   while (--i > next)
1531                     glyphs[i] = kCGFontIndexInvalid;
1533                   len--;
1534                   glyphs[i] = glyphs[len];
1535                   if (len == 0)
1536                     break;
1537                 }
1538             }
1539           if (i > len)
1540             while (i-- > 0)
1541               glyphs[i] = kCGFontIndexInvalid;
1543           nrows = cache->glyph.nrows;
1544           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1545           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1546           nrows++;
1547           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1548                                           sizeof (CGGlyph *) * nrows);
1549           cache->glyph.matrix[nrows - 1] = glyphs;
1550           cache->glyph.nrows = nrows;
1552           if (group)
1553             {
1554               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1555               dispatch_release (group);
1556             }
1557         }
1559       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1560     }
1561   else
1562     {
1563       uintptr_t key, value;
1564       int nshifts;
1565       CGGlyph glyph;
1567       if (cache->glyph.dictionary == NULL)
1568         cache->glyph.dictionary =
1569           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1570       key = c / NGLYPHS_IN_VALUE;
1571       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1572       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1573                                                 (const void *) key);
1574       glyph = (value >> nshifts);
1575       if (glyph == 0)
1576         {
1577           UniChar unichars[2];
1578           CGGlyph glyphs[2];
1579           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1581           if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1582             glyph = glyphs[0];
1583           if (glyph == 0)
1584             glyph = kCGFontIndexInvalid;
1586           value |= ((uintptr_t) glyph << nshifts);
1587           CFDictionarySetValue (cache->glyph.dictionary,
1588                                 (const void *) key, (const void *) value);
1589         }
1591       return glyph;
1592     }
1595 static CGGlyph
1596 macfont_get_glyph_for_cid (struct font *font, CTCharacterCollection collection,
1597                            CGFontIndex cid)
1599   struct macfont_info *macfont_info = (struct macfont_info *) font;
1600   CTFontRef macfont = macfont_info->macfont;
1602   /* Cache it? */
1603   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1606 static CFDataRef
1607 macfont_get_uvs_table (struct font *font, CTCharacterCollection *collection)
1609   struct macfont_info *macfont_info = (struct macfont_info *) font;
1610   CTFontRef macfont = macfont_info->macfont;
1611   struct macfont_cache *cache = macfont_info->cache;
1612   CFDataRef result = NULL;
1614   if (cache->uvs.table == NULL)
1615     {
1616       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1617       CTCharacterCollection uvs_collection =
1618         kCTCharacterCollectionIdentityMapping;
1620       if (uvs_table == NULL
1621           && mac_font_get_glyph_for_cid (macfont,
1622                                          kCTCharacterCollectionAdobeJapan1,
1623                                          6480) != kCGFontIndexInvalid)
1624         {
1625           /* If the glyph for U+4E55 is accessible via its CID 6480,
1626              then we use the Adobe-Japan1 UVS table, which maps a
1627              variation sequence to a CID, as a fallback.  */
1628           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1630           if (mac_uvs_table_adobe_japan1 == NULL)
1631             mac_uvs_table_adobe_japan1 =
1632               CFDataCreateWithBytesNoCopy (NULL,
1633                                            mac_uvs_table_adobe_japan1_bytes,
1634                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1635                                            kCFAllocatorNull);
1636           if (mac_uvs_table_adobe_japan1)
1637             {
1638               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1639               uvs_collection = kCTCharacterCollectionAdobeJapan1;
1640             }
1641         }
1642       if (uvs_table == NULL)
1643         cache->uvs.table = kCFNull;
1644       else
1645         cache->uvs.table = uvs_table;
1646       cache->uvs.collection = uvs_collection;
1647     }
1649   if (cache->uvs.table != kCFNull)
1650     {
1651       result = cache->uvs.table;
1652       *collection = cache->uvs.collection;
1653     }
1655   return result;
1658 static Lisp_Object macfont_get_cache (struct frame *);
1659 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1660 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1661 static Lisp_Object macfont_list_family (struct frame *);
1662 static void macfont_free_entity (Lisp_Object);
1663 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1664 static void macfont_close (struct font *);
1665 static int macfont_has_char (Lisp_Object, int);
1666 static unsigned macfont_encode_char (struct font *, int);
1667 static void macfont_text_extents (struct font *, unsigned int *, int,
1668                                   struct font_metrics *);
1669 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1670 static Lisp_Object macfont_shape (Lisp_Object);
1671 static int macfont_variation_glyphs (struct font *, int c,
1672                                      unsigned variations[256]);
1673 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1675 static struct font_driver macfont_driver =
1676   {
1677     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1678     0,                          /* case insensitive */
1679     macfont_get_cache,
1680     macfont_list,
1681     macfont_match,
1682     macfont_list_family,
1683     macfont_free_entity,
1684     macfont_open,
1685     macfont_close,
1686     NULL,                       /* prepare_face */
1687     NULL,                       /* done_face */
1688     macfont_has_char,
1689     macfont_encode_char,
1690     macfont_text_extents,
1691     macfont_draw,
1692     NULL,                       /* get_bitmap */
1693     NULL,                       /* free_bitmap */
1694     NULL,                       /* anchor_point */
1695     NULL,                       /* otf_capability */
1696     NULL,                       /* otf_drive */
1697     NULL,                       /* start_for_frame */
1698     NULL,                       /* end_for_frame */
1699     macfont_shape,
1700     NULL,                       /* check */
1701     macfont_variation_glyphs,
1702     macfont_filter_properties,
1703   };
1705 static Lisp_Object
1706 macfont_get_cache (struct frame * f)
1708   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1710   return (dpyinfo->name_list_element);
1713 static int
1714 macfont_get_charset (Lisp_Object registry)
1716   char *str = SSDATA (SYMBOL_NAME (registry));
1717   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1718   Lisp_Object regexp;
1719   int i, j;
1721   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1722     {
1723       if (str[i] == '.')
1724         re[j++] = '\\';
1725       else if (str[i] == '*')
1726         re[j++] = '.';
1727       re[j] = str[i];
1728       if (re[j] == '?')
1729         re[j] = '.';
1730     }
1731   re[j] = '\0';
1732   regexp = make_unibyte_string (re, j);
1733   for (i = 0; cf_charset_table[i].name; i++)
1734     if (fast_c_string_match_ignore_case
1735         (regexp, cf_charset_table[i].name,
1736          strlen (cf_charset_table[i].name)) >= 0)
1737       break;
1738   if (! cf_charset_table[i].name)
1739     return -1;
1740   if (! cf_charset_table[i].cf_charset)
1741     {
1742       int *uniquifier = cf_charset_table[i].uniquifier;
1743       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1744       CFIndex count = 0;
1745       CFStringRef string;
1746       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1748       if (! charset)
1749         return -1;
1750       for (j = 0; uniquifier[j]; j++)
1751         {
1752           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1753                                                         unichars + count);
1754           CFCharacterSetAddCharactersInRange (charset,
1755                                               CFRangeMake (uniquifier[j], 1));
1756         }
1758       string = CFStringCreateWithCharacters (NULL, unichars, count);
1759       if (! string)
1760         {
1761           CFRelease (charset);
1762           return -1;
1763         }
1764       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1765                                                                  charset);
1766       CFRelease (charset);
1767       /* CFCharacterSetCreateWithCharactersInString does not handle
1768          surrogate pairs properly as of Mac OS X 10.5.  */
1769       cf_charset_table[i].cf_charset_string = string;
1770     }
1771   return i;
1774 struct OpenTypeSpec
1776   Lisp_Object script;
1777   unsigned int script_tag, langsys_tag;
1778   int nfeatures[2];
1779   unsigned int *features[2];
1782 #define OTF_SYM_TAG(SYM, TAG)                               \
1783   do {                                                      \
1784     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1785     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1786   } while (0)
1788 #define OTF_TAG_STR(TAG, P)                     \
1789   do {                                          \
1790     (P)[0] = (char) (TAG >> 24);                \
1791     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1792     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1793     (P)[3] = (char) (TAG & 0xFF);               \
1794     (P)[4] = '\0';                              \
1795   } while (0)
1797 static struct OpenTypeSpec *
1798 macfont_get_open_type_spec (Lisp_Object otf_spec)
1800   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1801   Lisp_Object val;
1802   int i, j;
1803   bool negative;
1805   if (! spec)
1806     return NULL;
1807   spec->script = XCAR (otf_spec);
1808   if (! NILP (spec->script))
1809     {
1810       OTF_SYM_TAG (spec->script, spec->script_tag);
1811       val = assq_no_quit (spec->script, Votf_script_alist);
1812       if (CONSP (val) && SYMBOLP (XCDR (val)))
1813         spec->script = XCDR (val);
1814       else
1815         spec->script = Qnil;
1816     }
1817   else
1818     spec->script_tag = 0x44464C54;      /* "DFLT" */
1819   otf_spec = XCDR (otf_spec);
1820   spec->langsys_tag = 0;
1821   if (! NILP (otf_spec))
1822     {
1823       val = XCAR (otf_spec);
1824       if (! NILP (val))
1825         OTF_SYM_TAG (val, spec->langsys_tag);
1826       otf_spec = XCDR (otf_spec);
1827     }
1828   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1829   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1830     {
1831       Lisp_Object len;
1833       val = XCAR (otf_spec);
1834       if (NILP (val))
1835         continue;
1836       len = Flength (val);
1837       spec->features[i] =
1838         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1839          ? 0
1840          : malloc (XINT (len) * sizeof *spec->features[i]));
1841       if (! spec->features[i])
1842         {
1843           if (i > 0 && spec->features[0])
1844             free (spec->features[0]);
1845           free (spec);
1846           return NULL;
1847         }
1848       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1849         {
1850           if (NILP (XCAR (val)))
1851             negative = 1;
1852           else
1853             {
1854               unsigned int tag;
1856               OTF_SYM_TAG (XCAR (val), tag);
1857               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1858             }
1859         }
1860       spec->nfeatures[i] = j;
1861     }
1862   return spec;
1865 static CFMutableDictionaryRef
1866 macfont_create_attributes_with_spec (Lisp_Object spec)
1868   Lisp_Object tmp, extra;
1869   CFMutableArrayRef langarray = NULL;
1870   CFCharacterSetRef charset = NULL;
1871   CFStringRef charset_string = NULL;
1872   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1873   Lisp_Object script = Qnil;
1874   Lisp_Object registry;
1875   int cf_charset_idx, i;
1876   struct OpenTypeSpec *otspec = NULL;
1877   struct {
1878     enum font_property_index index;
1879     CFStringRef trait;
1880     CGPoint points[6];
1881   } numeric_traits[] =
1882       {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1883         {{-0.4, 50},            /* light */
1884          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1885          {0, 100},              /* normal */
1886          {0.24, 140},           /* (semi-bold + normal) / 2 */
1887          {0.4, 200},            /* bold */
1888          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1889        {FONT_SLANT_INDEX, kCTFontSlantTrait,
1890         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1891        {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1892         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1894   registry = AREF (spec, FONT_REGISTRY_INDEX);
1895   if (NILP (registry)
1896       || EQ (registry, Qascii_0)
1897       || EQ (registry, Qiso10646_1)
1898       || EQ (registry, Qunicode_bmp))
1899     cf_charset_idx = -1;
1900   else
1901     {
1902       CFStringRef lang;
1904       cf_charset_idx = macfont_get_charset (registry);
1905       if (cf_charset_idx < 0)
1906         goto err;
1907       charset = cf_charset_table[cf_charset_idx].cf_charset;
1908       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1909       lang = cf_charset_table[cf_charset_idx].lang;
1910       if (lang)
1911         {
1912           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1913           if (! langarray)
1914             goto err;
1915           CFArrayAppendValue (langarray, lang);
1916         }
1917     }
1919   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1920        CONSP (extra); extra = XCDR (extra))
1921     {
1922       Lisp_Object key, val;
1924       tmp = XCAR (extra);
1925       key = XCAR (tmp), val = XCDR (tmp);
1926       if (EQ (key, QClang))
1927         {
1928           if (! langarray)
1929             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1930           if (! langarray)
1931             goto err;
1932           if (SYMBOLP (val))
1933             val = list1 (val);
1934           for (; CONSP (val); val = XCDR (val))
1935             if (SYMBOLP (XCAR (val)))
1936               {
1937                 CFStringRef lang =
1938                   cfstring_create_with_string_noencode (SYMBOL_NAME
1939                                                         (XCAR (val)));
1941                 if (lang == NULL)
1942                   goto err;
1943                 CFArrayAppendValue (langarray, lang);
1944                 CFRelease (lang);
1945               }
1946         }
1947       else if (EQ (key, QCotf))
1948         {
1949           otspec = macfont_get_open_type_spec (val);
1950           if (! otspec)
1951             goto err;
1952           script = otspec->script;
1953         }
1954       else if (EQ (key, QCscript))
1955         script = val;
1956     }
1958   if (! NILP (script) && ! charset)
1959     {
1960       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1962       if (CONSP (chars) && CONSP (CDR (chars)))
1963         {
1964           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1965           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1967           if (! string || !cs)
1968             {
1969               if (string)
1970                 CFRelease (string);
1971               else if (cs)
1972                 CFRelease (cs);
1973               goto err;
1974             }
1975           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1976             if (CHARACTERP (XCAR (chars)))
1977               {
1978                 UniChar unichars[2];
1979                 CFIndex count =
1980                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1981                                                        unichars);
1982                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1984                 CFStringAppendCharacters (string, unichars, count);
1985                 CFCharacterSetAddCharactersInRange (cs, range);
1986               }
1987           charset = cs;
1988           /* CFCharacterSetCreateWithCharactersInString does not
1989              handle surrogate pairs properly as of Mac OS X 10.5.  */
1990           charset_string = string;
1991         }
1992     }
1994   attributes = CFDictionaryCreateMutable (NULL, 0,
1995                                           &kCFTypeDictionaryKeyCallBacks,
1996                                           &kCFTypeDictionaryValueCallBacks);
1997   if (! attributes)
1998     goto err;
2000   tmp = AREF (spec, FONT_FAMILY_INDEX);
2001   if (SYMBOLP (tmp) && ! NILP (tmp))
2002     {
2003       CFStringRef family = macfont_create_family_with_symbol (tmp);
2005       if (! family)
2006         goto err;
2007       CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
2008                             family);
2009       CFRelease (family);
2010     }
2012   traits = CFDictionaryCreateMutable (NULL, 4,
2013                                       &kCFTypeDictionaryKeyCallBacks,
2014                                       &kCFTypeDictionaryValueCallBacks);
2015   if (! traits)
2016     goto err;
2018   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
2019     {
2020       tmp = AREF (spec, numeric_traits[i].index);
2021       if (INTEGERP (tmp))
2022         {
2023           CGPoint *point = numeric_traits[i].points;
2024           CGFloat floatval = (XINT (tmp) >> 8); // XXX
2025           CFNumberRef num;
2027           while (point->y < floatval)
2028             point++;
2029           if (point == numeric_traits[i].points)
2030             point++;
2031           else if (point->y == CGFLOAT_MAX)
2032             point--;
2033           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
2034                                        * ((point->x - (point - 1)->x)
2035                                           / (point->y - (point - 1)->y)));
2036           if (floatval > 1.0)
2037             floatval = 1.0;
2038           else if (floatval < -1.0)
2039             floatval = -1.0;
2040           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2041           if (! num)
2042             goto err;
2043           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2044           CFRelease (num);
2045         }
2046     }
2047   if (CFDictionaryGetCount (traits))
2048     CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2050   if (charset)
2051     CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2052                           charset);
2053   if (charset_string)
2054     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2055                           charset_string);
2056   if (langarray)
2057     CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2059   goto finish;
2061  err:
2062   if (attributes)
2063     {
2064       CFRelease (attributes);
2065       attributes = NULL;
2066     }
2068  finish:
2069   if (langarray) CFRelease (langarray);
2070   if (charset && cf_charset_idx < 0) CFRelease (charset);
2071   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2072   if (traits) CFRelease (traits);
2073   if (otspec)
2074     {
2075       if (otspec->nfeatures[0] > 0)
2076         free (otspec->features[0]);
2077       if (otspec->nfeatures[1] > 0)
2078         free (otspec->features[1]);
2079       free (otspec);
2080     }
2082   return attributes;
2085 static Boolean
2086 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2087                                           CFCharacterSetRef charset,
2088                                           Lisp_Object chars,
2089                                           CFArrayRef languages)
2091   Boolean result = true;
2093   if (charset || VECTORP (chars))
2094     {
2095       CFCharacterSetRef desc_charset =
2096         CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2098       if (desc_charset == NULL)
2099         result = false;
2100       else
2101         {
2102           if (charset)
2103             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2104           else                  /* VECTORP (chars) */
2105             {
2106               ptrdiff_t j;
2108               for (j = 0; j < ASIZE (chars); j++)
2109                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2110                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2111                                                             XFASTINT (AREF (chars, j))))
2112                   break;
2113               if (j == ASIZE (chars))
2114                 result = false;
2115             }
2116           CFRelease (desc_charset);
2117         }
2118     }
2119   if (result && languages)
2120     result = mac_font_descriptor_supports_languages (desc, languages);
2122   return result;
2125 static int
2126 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2127                          CTFontSymbolicTraits sym_traits2)
2129   CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2130   int distance = 0;
2132   /* We prefer synthetic bold of italic to synthetic italic of bold
2133      when both bold and italic are available but bold-italic is not
2134      available.  */
2135   if (diff & kCTFontTraitBold)
2136     distance |= (1 << 0);
2137   if (diff & kCTFontTraitItalic)
2138     distance |= (1 << 1);
2139   if (diff & kCTFontTraitMonoSpace)
2140     distance |= (1 << 2);
2142   return distance;
2145 static Boolean
2146 macfont_closest_traits_index_p (CFArrayRef traits_array,
2147                                 CTFontSymbolicTraits target,
2148                                 CFIndex index)
2150   CFIndex i, count = CFArrayGetCount (traits_array);
2151   CTFontSymbolicTraits traits;
2152   int my_distance;
2154   traits = ((CTFontSymbolicTraits) (uintptr_t)
2155             CFArrayGetValueAtIndex (traits_array, index));
2156   my_distance = macfont_traits_distance (target, traits);
2158   for (i = 0; i < count; i++)
2159     if (i != index)
2160       {
2161         traits = ((CTFontSymbolicTraits) (uintptr_t)
2162                   CFArrayGetValueAtIndex (traits_array, i));
2163         if (macfont_traits_distance (target, traits) < my_distance)
2164           return false;
2165       }
2167   return true;
2170 static Lisp_Object
2171 macfont_list (struct frame *f, Lisp_Object spec)
2173   Lisp_Object val = Qnil, family, extra;
2174   int i, n;
2175   CFStringRef family_name = NULL;
2176   CFMutableDictionaryRef attributes = NULL, traits;
2177   Lisp_Object chars = Qnil;
2178   int spacing = -1;
2179   CTFontSymbolicTraits synth_sym_traits = 0;
2180   CFArrayRef families;
2181   CFIndex families_count;
2182   CFCharacterSetRef charset = NULL;
2183   CFArrayRef languages = NULL;
2185   block_input ();
2187   family = AREF (spec, FONT_FAMILY_INDEX);
2188   if (! NILP (family))
2189     {
2190       family_name = macfont_create_family_with_symbol (family);
2191       if (family_name == NULL)
2192         goto finish;
2193     }
2195   attributes = macfont_create_attributes_with_spec (spec);
2196   if (! attributes)
2197     goto finish;
2199   languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2201   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2202     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2204   traits = ((CFMutableDictionaryRef)
2205             CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2207   n = FONT_SLANT_NUMERIC (spec);
2208   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2209     {
2210       synth_sym_traits |= kCTFontTraitItalic;
2211       if (traits)
2212         CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2213     }
2215   n = FONT_WEIGHT_NUMERIC (spec);
2216   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2217     {
2218       synth_sym_traits |= kCTFontTraitBold;
2219       if (traits)
2220         CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2221     }
2223   if (languages
2224       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2225     {
2226       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2228       if (CFStringHasPrefix (language, CFSTR ("ja"))
2229           || CFStringHasPrefix (language, CFSTR ("ko"))
2230           || CFStringHasPrefix (language, CFSTR ("zh")))
2231         synth_sym_traits |= kCTFontTraitMonoSpace;
2232     }
2234   /* Create array of families.  */
2235   if (family_name)
2236     families = CFArrayCreate (NULL, (const void **) &family_name,
2237                               1, &kCFTypeArrayCallBacks);
2238   else
2239     {
2240       CFStringRef pref_family;
2241       CFIndex families_count, pref_family_index = -1;
2243       families = macfont_copy_available_families_cache ();
2244       if (families == NULL)
2245         goto err;
2247       families_count = CFArrayGetCount (families);
2249       /* Move preferred family to the front if exists.  */
2250       pref_family =
2251         mac_font_create_preferred_family_for_attributes (attributes);
2252       if (pref_family)
2253         {
2254           pref_family_index =
2255             CFArrayGetFirstIndexOfValue (families,
2256                                          CFRangeMake (0, families_count),
2257                                          pref_family);
2258           CFRelease (pref_family);
2259         }
2260       if (pref_family_index > 0)
2261         {
2262           CFMutableArrayRef mutable_families =
2263             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2265           if (mutable_families)
2266             {
2267               CFArrayAppendValue (mutable_families,
2268                                   CFArrayGetValueAtIndex (families,
2269                                                           pref_family_index));
2270               CFArrayAppendArray (mutable_families, families,
2271                                   CFRangeMake (0, pref_family_index));
2272               if (pref_family_index + 1 < families_count)
2273                 CFArrayAppendArray (mutable_families, families,
2274                                     CFRangeMake (pref_family_index + 1,
2275                                                  families_count
2276                                                  - (pref_family_index + 1)));
2277               CFRelease (families);
2278               families = mutable_families;
2279             }
2280         }
2281     }
2283   charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2284   if (charset)
2285     {
2286       CFRetain (charset);
2287       CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2288     }
2289   else
2290     {
2291       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2292       if (! NILP (val))
2293         {
2294           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2295           if (CONSP (val) && VECTORP (XCDR (val)))
2296             chars = XCDR (val);
2297         }
2298       val = Qnil;
2299     }
2301   if (languages)
2302     {
2303       CFRetain (languages);
2304       CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2305     }
2307   val = Qnil;
2308   extra = AREF (spec, FONT_EXTRA_INDEX);
2309   families_count = CFArrayGetCount (families);
2310   for (i = 0; i < families_count; i++)
2311     {
2312       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2313       CTFontDescriptorRef pat_desc;
2314       CFArrayRef descs;
2315       CFIndex descs_count;
2316       CFMutableArrayRef filtered_descs, traits_array;
2317       Lisp_Object entity;
2318       int j;
2320       CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2321                             family_name);
2322       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2323       if (! pat_desc)
2324         goto err;
2326       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2327          10.7 returns NULL if pat_desc represents the LastResort font.
2328          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2329          trailing "s") for such a font.  */
2330       if (!CFEqual (family_name, CFSTR ("LastResort")))
2331         descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2332       else
2333         {
2334           CTFontDescriptorRef lr_desc =
2335             CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2336           if (lr_desc)
2337             {
2338               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2339                                      &kCFTypeArrayCallBacks);
2340               CFRelease (lr_desc);
2341             }
2342           else
2343             descs = NULL;
2344         }
2345       CFRelease (pat_desc);
2346       if (! descs)
2347         continue;
2349       descs_count = CFArrayGetCount (descs);
2350       if (descs_count == 0
2351           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2352                                                         charset, chars,
2353                                                         languages))
2354         {
2355           CFRelease (descs);
2356           continue;
2357         }
2359       filtered_descs =
2360         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2361       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2362       for (j = 0; j < descs_count; j++)
2363         {
2364           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2365           CFDictionaryRef dict;
2366           CFNumberRef num;
2367           CTFontSymbolicTraits sym_traits;
2369           dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2370           if (dict == NULL)
2371             continue;
2373           num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2374           CFRelease (dict);
2375           if (num == NULL
2376               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2377             continue;
2379           if (spacing >= 0
2380               && !(synth_sym_traits & kCTFontTraitMonoSpace)
2381               && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2382                   != (spacing >= FONT_SPACING_MONO)))
2383             continue;
2385           /* Don't use a color bitmap font unless its family is
2386              explicitly specified.  */
2387           if ((sym_traits & kCTFontTraitColorGlyphs) && NILP (family))
2388             continue;
2390           if (j > 0
2391               && !macfont_supports_charset_and_languages_p (desc, charset,
2392                                                             chars, languages))
2393             continue;
2395           CFArrayAppendValue (filtered_descs, desc);
2396           CFArrayAppendValue (traits_array,
2397                               (const void *) (uintptr_t) sym_traits);
2398         }
2400       CFRelease (descs);
2401       descs = filtered_descs;
2402       descs_count = CFArrayGetCount (descs);
2404       for (j = 0; j < descs_count; j++)
2405         {
2406           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2407           CTFontSymbolicTraits sym_traits =
2408             ((CTFontSymbolicTraits) (uintptr_t)
2409              CFArrayGetValueAtIndex (traits_array, j));
2410           CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2412           mask_min = ((synth_sym_traits ^ sym_traits)
2413                       & (kCTFontTraitItalic | kCTFontTraitBold));
2414           if (FONT_SLANT_NUMERIC (spec) < 0)
2415             mask_min &= ~kCTFontTraitItalic;
2416           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2417             mask_min &= ~kCTFontTraitBold;
2419           mask_max = (synth_sym_traits & ~sym_traits);
2420           /* Synthetic bold does not work for bitmap-only fonts on Mac
2421              OS X 10.6.  */
2422           if ((mask_min ^ mask_max) & kCTFontTraitBold)
2423             {
2424               CFNumberRef format =
2425                 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2427               if (format)
2428                 {
2429                   uint32_t format_val;
2431                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2432                                         &format_val)
2433                       && format_val == kCTFontFormatBitmap)
2434                     mask_max &= ~kCTFontTraitBold;
2435                 }
2436             }
2437           if (spacing >= 0)
2438             mask_min |= (mask_max & kCTFontTraitMonoSpace);
2440           for (mmask = (mask_min & kCTFontTraitMonoSpace);
2441                mmask <= (mask_max & kCTFontTraitMonoSpace);
2442                mmask += kCTFontTraitMonoSpace)
2443             for (bmask = (mask_min & kCTFontTraitBold);
2444                  bmask <= (mask_max & kCTFontTraitBold);
2445                  bmask += kCTFontTraitBold)
2446               for (imask = (mask_min & kCTFontTraitItalic);
2447                    imask <= (mask_max & kCTFontTraitItalic);
2448                    imask += kCTFontTraitItalic)
2449                 {
2450                   CTFontSymbolicTraits synth = (imask | bmask | mmask);
2452                   if (synth == 0
2453                       || macfont_closest_traits_index_p (traits_array,
2454                                                          (sym_traits | synth),
2455                                                          j))
2456                     {
2457                       entity = macfont_descriptor_entity (desc, extra, synth);
2458                       if (! NILP (entity))
2459                         val = Fcons (entity, val);
2460                     }
2461                 }
2462         }
2464       CFRelease (traits_array);
2465       CFRelease (descs);
2466     }
2468   CFRelease (families);
2469   val = Fnreverse (val);
2470   goto finish;
2471  err:
2472   val = Qnil;
2474  finish:
2475   FONT_ADD_LOG ("macfont-list", spec, val);
2476   if (charset) CFRelease (charset);
2477   if (languages) CFRelease (languages);
2478   if (attributes) CFRelease (attributes);
2479   if (family_name) CFRelease (family_name);
2481   unblock_input ();
2483   return val;
2486 static Lisp_Object
2487 macfont_match (struct frame * frame, Lisp_Object spec)
2489   Lisp_Object entity = Qnil;
2490   CFMutableDictionaryRef attributes;
2491   CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2493   block_input ();
2495   attributes = macfont_create_attributes_with_spec (spec);
2496   if (attributes)
2497     {
2498       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2499       CFRelease (attributes);
2500     }
2501   if (pat_desc)
2502     {
2503       desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2504       CFRelease (pat_desc);
2505     }
2506   if (desc)
2507     {
2508       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2509                                           0);
2510       CFRelease (desc);
2511     }
2512   unblock_input ();
2514   FONT_ADD_LOG ("macfont-match", spec, entity);
2515   return entity;
2518 static Lisp_Object
2519 macfont_list_family (struct frame *frame)
2521   Lisp_Object list = Qnil;
2522   CFArrayRef families;
2524   block_input ();
2526   families = macfont_copy_available_families_cache ();
2527   if (families)
2528     {
2529       CFIndex i, count = CFArrayGetCount (families);
2531       for (i = 0; i < count; i++)
2532         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2533       CFRelease (families);
2534     }
2536   unblock_input ();
2538   return list;
2541 static void
2542 macfont_free_entity (Lisp_Object entity)
2544   Lisp_Object val = assq_no_quit (QCfont_entity,
2545                                   AREF (entity, FONT_EXTRA_INDEX));
2546   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2548   block_input ();
2549   CFRelease (name);
2550   unblock_input ();
2553 static Lisp_Object
2554 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2556   Lisp_Object val, font_object;
2557   CFStringRef font_name;
2558   struct macfont_info *macfont_info = NULL;
2559   struct font *font;
2560   int size;
2561   CTFontRef macfont;
2562   CTFontSymbolicTraits sym_traits;
2563   char name[256];
2564   int len, i, total_width;
2565   CGGlyph glyph;
2566   CGFloat ascent, descent, leading;
2568   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2569   if (! CONSP (val)
2570       || XTYPE (XCDR (val)) != Lisp_Misc
2571       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2572     return Qnil;
2573   font_name = XSAVE_POINTER (XCDR (val), 0);
2574   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2576   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2577   if (size == 0)
2578     size = pixel_size;
2580   block_input ();
2581   macfont = CTFontCreateWithName (font_name, size, NULL);
2582   if (macfont)
2583     {
2584       int fontsize = (int) [((NSFont *) macfont) pointSize];
2585       if (fontsize != size) size = fontsize;
2586     }
2587   unblock_input ();
2588   if (! macfont)
2589     return Qnil;
2591   font_object = font_build_object (VECSIZE (struct macfont_info),
2592                                    Qmac_ct, entity, size);
2593   font = XFONT_OBJECT (font_object);
2594   font->pixel_size = size;
2595   font->driver = &macfont_driver;
2596   font->encoding_charset = font->repertory_charset = -1;
2598   block_input ();
2600   macfont_info = (struct macfont_info *) font;
2601   macfont_info->macfont = macfont;
2602   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2604   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2605   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2606     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2607                                                                   size);
2608   else
2609     macfont_info->screen_font = NULL;
2610   macfont_info->cache = macfont_lookup_cache (font_name);
2611   macfont_retain_cache (macfont_info->cache);
2612   macfont_info->metrics = NULL;
2613   macfont_info->metrics_nrows = 0;
2614   macfont_info->synthetic_italic_p = 0;
2615   macfont_info->synthetic_bold_p = 0;
2616   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2617   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2618   if (!(sym_traits & kCTFontTraitItalic)
2619       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2620     macfont_info->synthetic_italic_p = 1;
2621   if (!(sym_traits & kCTFontTraitBold)
2622       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2623     macfont_info->synthetic_bold_p = 1;
2624   if (sym_traits & kCTFontTraitMonoSpace)
2625     macfont_info->spacing = MACFONT_SPACING_MONO;
2626   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2627            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2628                == FONT_SPACING_SYNTHETIC_MONO))
2629     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2630   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2631     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2632   else
2633     {
2634       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2635       if (CONSP (val))
2636         macfont_info->antialias =
2637           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2638     }
2639   macfont_info->color_bitmap_p = 0;
2640   if (sym_traits & kCTFontTraitColorGlyphs)
2641     macfont_info->color_bitmap_p = 1;
2643   glyph = macfont_get_glyph_for_character (font, ' ');
2644   if (glyph != kCGFontIndexInvalid)
2645     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2646   else
2647     /* dirty workaround */
2648     font->space_width = pixel_size;
2650   total_width = font->space_width;
2651   for (i = 1; i < 95; i++)
2652     {
2653       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2654       if (glyph == kCGFontIndexInvalid)
2655         break;
2656       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2657     }
2658   if (i == 95)
2659     font->average_width = total_width / 95;
2660   else
2661     font->average_width = font->space_width; /* XXX */
2663   if (!(macfont_info->screen_font
2664         && mac_screen_font_get_metrics (macfont_info->screen_font,
2665                                         &ascent, &descent, &leading)))
2666     {
2667       CFStringRef family_name;
2669       ascent = CTFontGetAscent (macfont);
2670       descent = CTFontGetDescent (macfont);
2671       leading = CTFontGetLeading (macfont);
2672       /* AppKit and WebKit do some adjustment to the heights of
2673          Courier, Helvetica, and Times.  */
2674       family_name = CTFontCopyFamilyName (macfont);
2675       if (family_name)
2676         {
2677           if (CFEqual (family_name, CFSTR ("Courier"))
2678               || CFEqual (family_name, CFSTR ("Helvetica"))
2679               || CFEqual (family_name, CFSTR ("Times")))
2680             ascent += (ascent + descent) * .15f;
2681           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2682             {
2683               leading *= .25f;
2684               ascent += leading;
2685             }
2686           CFRelease (family_name);
2687         }
2688     }
2689   font->ascent = ascent + 0.5f;
2690   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2691   if (CONSP (val) && !NILP (XCDR (val)))
2692     font->descent = descent + 0.5f;
2693   else
2694     font->descent = descent + leading + 0.5f;
2695   font->height = font->ascent + font->descent;
2697   font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2698   font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2700   unblock_input ();
2702   /* Unfortunately Xft doesn't provide a way to get minimum char
2703      width.  So, we use space_width instead.  */
2704   font->min_width = font->max_width = font->space_width; /* XXX */
2706   font->baseline_offset = 0;
2707   font->relative_compose = 0;
2708   font->default_ascent = 0;
2709   font->vertical_centering = 0;
2711   return font_object;
2714 static void
2715 macfont_close (struct font *font)
2717   struct macfont_info *macfont_info = (struct macfont_info *) font;
2719   if (macfont_info->cache)
2720     {
2721       int i;
2723       block_input ();
2724       CFRelease (macfont_info->macfont);
2725       CGFontRelease (macfont_info->cgfont);
2726       if (macfont_info->screen_font)
2727         CFRelease (macfont_info->screen_font);
2728       macfont_release_cache (macfont_info->cache);
2729       for (i = 0; i < macfont_info->metrics_nrows; i++)
2730         if (macfont_info->metrics[i])
2731           xfree (macfont_info->metrics[i]);
2732       if (macfont_info->metrics)
2733         xfree (macfont_info->metrics);
2734       macfont_info->cache = NULL;
2735       unblock_input ();
2736     }
2739 static int
2740 macfont_has_char (Lisp_Object font, int c)
2742   int result;
2743   CFCharacterSetRef charset;
2745   block_input ();
2746   if (FONT_ENTITY_P (font))
2747     {
2748       Lisp_Object val;
2749       CFStringRef name;
2751       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2752       val = XCDR (val);
2753       name = XSAVE_POINTER (val, 0);
2754       charset = macfont_get_cf_charset_for_name (name);
2755     }
2756   else
2757     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2759   result = CFCharacterSetIsLongCharacterMember (charset, c);
2760   unblock_input ();
2762   return result;
2765 static unsigned
2766 macfont_encode_char (struct font *font, int c)
2768   CGGlyph glyph;
2770   block_input ();
2771   glyph = macfont_get_glyph_for_character (font, c);
2772   unblock_input ();
2774   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2777 static void
2778 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2779                       struct font_metrics *metrics)
2781   int width, i;
2783   block_input ();
2784   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2785   for (i = 1; i < nglyphs; i++)
2786     {
2787       struct font_metrics m;
2788       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2789                                      NULL, 0);
2791       if (metrics)
2792         {
2793           if (width + m.lbearing < metrics->lbearing)
2794             metrics->lbearing = width + m.lbearing;
2795           if (width + m.rbearing > metrics->rbearing)
2796             metrics->rbearing = width + m.rbearing;
2797           if (m.ascent > metrics->ascent)
2798             metrics->ascent = m.ascent;
2799           if (m.descent > metrics->descent)
2800             metrics->descent = m.descent;
2801         }
2802       width += w;
2803     }
2804   unblock_input ();
2806   if (metrics)
2807     metrics->width = width;
2810 static int
2811 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2812               bool with_background)
2814   struct frame * f = s->f;
2815   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2816   CGRect background_rect;
2817   CGPoint text_position;
2818   CGGlyph *glyphs;
2819   CGPoint *positions;
2820   CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2821   bool no_antialias_p =
2822     (NILP (ns_antialias_text)
2823      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2824      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2825          && font_size <= macfont_antialias_threshold));
2826   int len = to - from;
2827   struct face *face = s->face;
2828   CGContextRef context;
2830   block_input ();
2832   if (with_background)
2833     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2834                                   s->width, FONT_HEIGHT (s->font));
2835   else
2836     background_rect = CGRectNull;
2838   text_position = CGPointMake (x, -y);
2839   glyphs = xmalloc (sizeof (CGGlyph) * len);
2840   {
2841     CGFloat advance_delta = 0;
2842     int i;
2843     CGFloat total_width = 0;
2845     positions = xmalloc (sizeof (CGPoint) * len);
2846     for (i = 0; i < len; i++)
2847       {
2848         int width;
2850         glyphs[i] = s->char2b[from + i];
2851         width = (s->padding_p ? 1
2852                  : macfont_glyph_extents (s->font, glyphs[i],
2853                                           NULL, &advance_delta,
2854                                           no_antialias_p));
2855         positions[i].x = total_width + advance_delta;
2856         positions[i].y = 0;
2857         total_width += width;
2858       }
2859   }
2861   context = [[NSGraphicsContext currentContext] graphicsPort];
2862   CGContextSaveGState (context);
2864   if (!CGRectIsNull (background_rect))
2865     {
2866       if (s->hl == DRAW_MOUSE_FACE)
2867         {
2868           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2869           if (!face)
2870             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2871         }
2872       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2873       CGContextFillRects (context, &background_rect, 1);
2874     }
2876   if (macfont_info->cgfont)
2877     {
2878       CGAffineTransform atfm;
2880       CGContextScaleCTM (context, 1, -1);
2881       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2882       if (macfont_info->synthetic_italic_p)
2883         atfm = synthetic_italic_atfm;
2884       else
2885         atfm = CGAffineTransformIdentity;
2886       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2887         {
2888           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2889           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2890           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2891         }
2892       if (no_antialias_p)
2893         CGContextSetShouldAntialias (context, false);
2895       CGContextSetTextMatrix (context, atfm);
2896       CGContextSetTextPosition (context, text_position.x, text_position.y);
2898 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2899       if (macfont_info->color_bitmap_p
2900 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2901           && CTFontDrawGlyphs != NULL
2902 #endif
2903           )
2904         {
2905           if (len > 0)
2906             {
2907               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2908                                 context);
2909             }
2910         }
2911       else
2912 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2913         {
2914           CGContextSetFont (context, macfont_info->cgfont);
2915           CGContextSetFontSize (context, font_size);
2916           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2917         }
2918     }
2921   xfree (glyphs);
2922   xfree (positions);
2923   CGContextRestoreGState (context);
2925   unblock_input ();
2927   return len;
2930 static Lisp_Object
2931 macfont_shape (Lisp_Object lgstring)
2933   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2934   struct macfont_info *macfont_info = (struct macfont_info *) font;
2935   CTFontRef macfont = macfont_info->macfont;
2936   ptrdiff_t glyph_len, len, i, j;
2937   CFIndex nonbmp_len;
2938   UniChar *unichars;
2939   CFIndex *nonbmp_indices;
2940   CFStringRef string;
2941   CFIndex used = 0;
2942   struct mac_glyph_layout *glyph_layouts;
2944   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2945   nonbmp_len = 0;
2946   for (i = 0; i < glyph_len; i++)
2947     {
2948       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2950       if (NILP (lglyph))
2951         break;
2952       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2953         nonbmp_len++;
2954     }
2956   len = i;
2958   if (INT_MAX / 2 < len)
2959     memory_full (SIZE_MAX);
2961   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2962   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2963   for (i = j = 0; i < len; i++)
2964     {
2965       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2967       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2968         {
2969           nonbmp_indices[j] = i + j;
2970           j++;
2971         }
2972     }
2973   nonbmp_indices[j] = len + j;  /* sentinel */
2975   block_input ();
2977   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2978                                                kCFAllocatorNull);
2979   if (string)
2980     {
2981       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2982       if (macfont_info->screen_font)
2983         used = mac_screen_font_shape (macfont_info->screen_font, string,
2984                                       glyph_layouts, glyph_len);
2985       else
2986         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2987       CFRelease (string);
2988     }
2990   unblock_input ();
2992   if (used == 0)
2993     return Qnil;
2995   block_input ();
2997   for (i = 0; i < used; i++)
2998     {
2999       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
3000       struct mac_glyph_layout *gl = glyph_layouts + i;
3001       EMACS_INT from, to;
3002       struct font_metrics metrics;
3003       int xoff, yoff, wadjust;
3005       if (NILP (lglyph))
3006         {
3007           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
3008           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
3009         }
3011       from = gl->comp_range.location;
3012       /* Convert UTF-16 index to UTF-32.  */
3013       j = 0;
3014       while (nonbmp_indices[j] < from)
3015         j++;
3016       from -= j;
3017       LGLYPH_SET_FROM (lglyph, from);
3019       to = gl->comp_range.location + gl->comp_range.length;
3020       /* Convert UTF-16 index to UTF-32.  */
3021       while (nonbmp_indices[j] < to)
3022         j++;
3023       to -= j;
3024       LGLYPH_SET_TO (lglyph, to - 1);
3026       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3027          the composition is trivial.  */
3028       {
3029         UTF32Char c;
3031         if (unichars[gl->string_index] >= 0xD800
3032             && unichars[gl->string_index] < 0xDC00)
3033           c = (((unichars[gl->string_index] - 0xD800) << 10)
3034                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3035         else
3036           c = unichars[gl->string_index];
3037         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3038           c = 0;
3039         LGLYPH_SET_CHAR (lglyph, c);
3040       }
3042       {
3043         unsigned long cc = gl->glyph_id;
3044         LGLYPH_SET_CODE (lglyph, cc);
3045       }
3047       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3048       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3049       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3050       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3051       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3052       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3054       xoff = lround (gl->advance_delta);
3055       yoff = lround (- gl->baseline_delta);
3056       wadjust = lround (gl->advance);
3057       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3058         {
3059           Lisp_Object vec;
3061           vec = Fmake_vector (make_number (3), Qnil);
3062           ASET (vec, 0, make_number (xoff));
3063           ASET (vec, 1, make_number (yoff));
3064           ASET (vec, 2, make_number (wadjust));
3065           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3066         }
3067     }
3069   unblock_input ();
3071   return make_number (used);
3074 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3075 typedef UInt8 UINT24[3];
3077 #pragma pack(push, 1)
3078 struct variation_selector_record
3080   UINT24 var_selector;
3081   UInt32 default_uvs_offset, non_default_uvs_offset;
3083 struct uvs_table
3085   UInt16 format;
3086   UInt32 length, num_var_selector_records;
3087   struct variation_selector_record variation_selector_records[1];
3089 #define SIZEOF_UVS_TABLE_HEADER                                         \
3090   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3092 struct unicode_value_range
3094   UINT24 start_unicode_value;
3095   UInt8 additional_count;
3097 struct default_uvs_table {
3098   UInt32 num_unicode_value_ranges;
3099   struct unicode_value_range unicode_value_ranges[1];
3101 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3102   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3104 struct uvs_mapping
3106   UINT24 unicode_value;
3107   UInt16 glyph_id;
3109 struct non_default_uvs_table
3111   UInt32 num_uvs_mappings;
3112   struct uvs_mapping uvs_mappings[1];
3114 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3115   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3116 #pragma pack(pop)
3118 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3119 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3120    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3121    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3122 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3123 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3124 /* Succeeding one byte should also be accessible.  */
3125 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3126 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3128 /* Return UVS subtable for the specified FONT.  If the subtable is not
3129    found or ill-formatted, then return NULL.  */
3131 static CFDataRef
3132 mac_font_copy_uvs_table (CTFontRef font)
3134   CFDataRef cmap_table, uvs_table = NULL;
3136   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3137                                 kCTFontTableOptionNoOptions);
3138   if (cmap_table)
3139     {
3140       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3141       struct uvs_table *uvs;
3142       struct variation_selector_record *records;
3143       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3145 #if __LP64__
3146       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3147         goto finish;
3148 #endif
3150       cmap_len = CFDataGetLength (cmap_table);
3151       if (sizeof_sfntCMapHeader > cmap_len)
3152         goto finish;
3154       ntables = BUINT16_VALUE (cmap->numTables);
3155       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3156                      / sizeof_sfntCMapEncoding))
3157         goto finish;
3159       for (i = 0; i < ntables; i++)
3160         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3161              == kFontUnicodePlatform)
3162             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3163                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3164           {
3165             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3166             break;
3167           }
3168       if (i == ntables
3169           || uvs_offset > cmap_len
3170           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3171         goto finish;
3173       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3174       uvs_len = BUINT32_VALUE (uvs->length);
3175       if (uvs_len > cmap_len - uvs_offset
3176           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3177         goto finish;
3179       if (BUINT16_VALUE (uvs->format) != 14)
3180         goto finish;
3182       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3183       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3184                       / sizeof (struct variation_selector_record)))
3185         goto finish;
3187       records = uvs->variation_selector_records;
3188       for (i = 0; i < nrecords; i++)
3189         {
3190           UInt32 default_uvs_offset, non_default_uvs_offset;
3192           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3193           if (default_uvs_offset)
3194             {
3195               struct default_uvs_table *default_uvs;
3196               UInt32 nranges;
3198               if (default_uvs_offset > uvs_len
3199                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3200                       > uvs_len - default_uvs_offset))
3201                 goto finish;
3203               default_uvs = ((struct default_uvs_table *)
3204                              ((UInt8 *) uvs + default_uvs_offset));
3205               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3206               if (nranges > ((uvs_len - default_uvs_offset
3207                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3208                              / sizeof (struct unicode_value_range)))
3209                 goto finish;
3210               /* Now 2 * nranges can't overflow, so we can safely use
3211                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3212                  mac_font_get_glyphs_for_variants.  */
3213             }
3215           non_default_uvs_offset =
3216             BUINT32_VALUE (records[i].non_default_uvs_offset);
3217           if (non_default_uvs_offset)
3218             {
3219               struct non_default_uvs_table *non_default_uvs;
3220               UInt32 nmappings;
3222               if (non_default_uvs_offset > uvs_len
3223                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3224                       > uvs_len - non_default_uvs_offset))
3225                 goto finish;
3227               non_default_uvs = ((struct non_default_uvs_table *)
3228                                  ((UInt8 *) uvs + non_default_uvs_offset));
3229               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3230               if (nmappings > ((uvs_len - non_default_uvs_offset
3231                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3232                                / sizeof (struct uvs_mapping)))
3233                 goto finish;
3234               /* Now 2 * nmappings can't overflow, so we can safely
3235                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3236                  in mac_font_get_glyphs_for_variants.  */
3237             }
3238         }
3240       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3242     finish:
3243       CFRelease (cmap_table);
3244     }
3246   return uvs_table;
3249 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3250    sequence consisting of the given base character C and each
3251    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3252    result (explained below) into the corresponding GLYPHS[i].  If the
3253    entry is found in the Default UVS Table, then the result is 0.  If
3254    the entry is found in the Non-Default UVS Table, then the result is
3255    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3256    elements in SELECTORS must be sorted in strictly increasing
3257    order.  */
3259 static void
3260 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3261                                   const UTF32Char selectors[], CGGlyph glyphs[],
3262                                   CFIndex count)
3264   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3265   struct variation_selector_record *records = uvs->variation_selector_records;
3266   CFIndex i;
3267   UInt32 ir, nrecords;
3268   dispatch_queue_t queue =
3269     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3270   dispatch_group_t group = dispatch_group_create ();
3272   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3273   i = 0;
3274   ir = 0;
3275   while (i < count && ir < nrecords)
3276     {
3277       UInt32 default_uvs_offset, non_default_uvs_offset;
3279       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3280         {
3281           glyphs[i++] = kCGFontIndexInvalid;
3282           continue;
3283         }
3284       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3285         {
3286           ir++;
3287           continue;
3288         }
3290       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3291       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3292       non_default_uvs_offset =
3293         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3294       dispatch_group_async (group, queue, ^{
3295           glyphs[i] = kCGFontIndexInvalid;
3297           if (default_uvs_offset)
3298             {
3299               struct default_uvs_table *default_uvs =
3300                 (struct default_uvs_table *) ((UInt8 *) uvs
3301                                               + default_uvs_offset);
3302               struct unicode_value_range *ranges =
3303                 default_uvs->unicode_value_ranges;
3304               UInt32 lo, hi;
3306               lo = 0;
3307               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3308               while (lo < hi)
3309                 {
3310                   UInt32 mid = (lo + hi) / 2;
3312                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3313                     hi = mid;
3314                   else
3315                     lo = mid + 1;
3316                 }
3317               if (hi > 0
3318                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3319                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3320                 glyphs[i] = 0;
3321             }
3323           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3324             {
3325               struct non_default_uvs_table *non_default_uvs =
3326                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3327                                                   + non_default_uvs_offset);
3328               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3329               UInt32 lo, hi;
3331               lo = 0;
3332               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3333               while (lo < hi)
3334                 {
3335                   UInt32 mid = (lo + hi) / 2;
3337                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3338                     hi = mid;
3339                   else
3340                     lo = mid + 1;
3341                 }
3342               if (hi > 0 &&
3343                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3344                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3345             }
3346         });
3347       i++;
3348       ir++;
3349     }
3350   while (i < count)
3351     glyphs[i++] = kCGFontIndexInvalid;
3352   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3353   dispatch_release (group);
3356 static int
3357 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3359   CFDataRef uvs_table;
3360   CTCharacterCollection uvs_collection;
3361   int i, n = 0;
3363   block_input ();
3364   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3366   if (uvs_table)
3367     {
3368       UTF32Char selectors[256];
3369       CGGlyph glyphs[256];
3371       for (i = 0; i < 16; i++)
3372         selectors[i] = 0xFE00 + i;
3373       for (; i < 256; i++)
3374         selectors[i] = 0xE0100 + (i - 16);
3375       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3376       for (i = 0; i < 256; i++)
3377         {
3378           CGGlyph glyph = glyphs[i];
3380           if (uvs_collection != kCTCharacterCollectionIdentityMapping
3381               && glyph != kCGFontIndexInvalid)
3382             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3383           if (glyph == kCGFontIndexInvalid)
3384             variations[i] = 0;
3385           else
3386             {
3387               variations[i] = (glyph ? glyph
3388                                : macfont_get_glyph_for_character (font, c));
3389               n++;
3390             }
3391         }
3392     }
3393   unblock_input ();
3395   return n;
3398 static const char *const macfont_booleans[] = {
3399   ":antialias",
3400   ":minspace",
3401   NULL,
3404 static const char *const macfont_non_booleans[] = {
3405   ":lang",
3406   ":script",
3407   ":destination",
3408   NULL,
3411 static void
3412 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3414   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3417 static Boolean
3418 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3419                                         CFArrayRef languages)
3421   Boolean result = true;
3422   CFArrayRef desc_languages =
3423     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3425   if (desc_languages == NULL)
3426     result = false;
3427   else
3428     {
3429       CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3430       CFIndex i, languages_count = CFArrayGetCount (languages);
3432       for (i = 0; i < languages_count; i++)
3433         {
3434           CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3436           if (!CFArrayContainsValue (desc_languages, range, language)
3437               /* PingFang SC contains "zh" and "zh-Hant" as covered
3438                  languages, but does not contain "zh-Hans".  */
3439               && !(CFEqual (language, CFSTR ("zh-Hans"))
3440                    && CFArrayContainsValue (desc_languages, range,
3441                                             CFSTR ("zh"))))
3442             {
3443               result = false;
3444               break;
3445             }
3446         }
3447       CFRelease (desc_languages);
3448     }
3450   return result;
3453 static CFStringRef
3454 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3456   CFStringRef result = NULL;
3457   CFStringRef charset_string =
3458     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3460   if (charset_string && CFStringGetLength (charset_string) > 0)
3461     {
3462       CFStringRef keys[] = {
3463 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3464         kCTLanguageAttributeName
3465 #else
3466         CFSTR ("NSLanguage")
3467 #endif
3468       };
3469       CFTypeRef values[] = {NULL};
3470       CFIndex num_values = 0;
3471       CFArrayRef languages
3472         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3474       if (languages && CFArrayGetCount (languages) > 0)
3475         {
3476           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3477             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3478           else
3479             {
3480               CFCharacterSetRef charset =
3481                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3483               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3484             }
3485         }
3486       if (result == NULL)
3487         {
3488           CFAttributedStringRef attr_string = NULL;
3489           CTLineRef ctline = NULL;
3490           CFDictionaryRef attrs
3491             = CFDictionaryCreate (NULL, (const void **) keys,
3492                                   (const void **) values, num_values,
3493                                   &kCFTypeDictionaryKeyCallBacks,
3494                                   &kCFTypeDictionaryValueCallBacks);
3496           if (attrs)
3497             {
3498               attr_string = CFAttributedStringCreate (NULL, charset_string,
3499                                                       attrs);
3500               CFRelease (attrs);
3501             }
3502           if (attr_string)
3503             {
3504               ctline = CTLineCreateWithAttributedString (attr_string);
3505               CFRelease (attr_string);
3506             }
3507           if (ctline)
3508             {
3509               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3510               CFIndex i, nruns = CFArrayGetCount (runs);
3511               CTFontRef font;
3513               for (i = 0; i < nruns; i++)
3514                 {
3515                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3516                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3517                   CTFontRef font_in_run;
3519                   if (attributes == NULL)
3520                     break;
3521                   font_in_run =
3522                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3523                   if (font_in_run == NULL)
3524                     break;
3525                   if (i == 0)
3526                     font = font_in_run;
3527                   else if (!mac_font_equal_in_postscript_name (font,
3528                                                                font_in_run))
3529                     break;
3530                 }
3531               if (nruns > 0 && i == nruns)
3532                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3533               CFRelease (ctline);
3534             }
3535         }
3536     }
3538   return result;
3541 static inline double
3542 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3544   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3545                                      &glyph, NULL, 1);
3548 static inline CGRect
3549 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3551   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3552                                           &glyph, NULL, 1);
3555 static CFArrayRef
3556 mac_font_create_available_families (void)
3558   CFMutableArrayRef families = NULL;
3559   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3561   if (orig_families)
3562     {
3563       CFIndex i, count = CFArrayGetCount (orig_families);
3565       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3566       if (families)
3567         for (i = 0; i < count; i++)
3568           {
3569             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3571             if (!CFStringHasPrefix (family, CFSTR ("."))
3572                 && (CTFontManagerCompareFontFamilyNames (family,
3573                                                          CFSTR ("LastResort"),
3574                                                          NULL)
3575                     != kCFCompareEqualTo))
3576               CFArrayAppendValue (families, family);
3577           }
3578       CFRelease (orig_families);
3579     }
3581   return families;
3584 static Boolean
3585 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3587   Boolean result;
3588   CFStringRef name1, name2;
3590   if (font1 == font2)
3591     return true;
3593   result = false;
3594   name1 = CTFontCopyPostScriptName (font1);
3595   if (name1)
3596     {
3597       name2 = CTFontCopyPostScriptName (font2);
3598       if (name2)
3599         {
3600           result = CFEqual (name1, name2);
3601           CFRelease (name2);
3602         }
3603       CFRelease (name1);
3604     }
3606   return result;
3609 static CTLineRef
3610 mac_font_create_line_with_string_and_font (CFStringRef string,
3611                                            CTFontRef macfont)
3613   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3614   CFTypeRef values[] = {NULL, NULL};
3615   CFDictionaryRef attributes = NULL;
3616   CFAttributedStringRef attr_string = NULL;
3617   CTLineRef ctline = NULL;
3618   float float_zero = 0.0f;
3620   values[0] = macfont;
3621   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3622   if (values[1])
3623     {
3624       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3625                                        (const void **) values,
3626                                        ARRAYELTS (keys),
3627                                        &kCFTypeDictionaryKeyCallBacks,
3628                                        &kCFTypeDictionaryValueCallBacks);
3629       CFRelease (values[1]);
3630     }
3631   if (attributes)
3632     {
3633       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3634       CFRelease (attributes);
3635     }
3636   if (attr_string)
3637     {
3638       ctline = CTLineCreateWithAttributedString (attr_string);
3639       CFRelease (attr_string);
3640     }
3641   if (ctline)
3642     {
3643       /* Abandon if ctline contains some fonts other than the
3644          specified one.  */
3645       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3646       CFIndex i, nruns = CFArrayGetCount (runs);
3648       for (i = 0; i < nruns; i++)
3649         {
3650           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3651           CFDictionaryRef attributes = CTRunGetAttributes (run);
3652           CTFontRef font_in_run;
3654           if (attributes == NULL)
3655             break;
3656           font_in_run =
3657             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3658           if (font_in_run == NULL)
3659             break;
3660           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3661             break;
3662         }
3663       if (i < nruns)
3664         {
3665           CFRelease (ctline);
3666           ctline = NULL;
3667         }
3668     }
3670   return ctline;
3673 static CFIndex
3674 mac_font_shape (CTFontRef font, CFStringRef string,
3675                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3677   CFIndex used, result = 0;
3678   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3680   if (ctline == NULL)
3681     return 0;
3683   used = CTLineGetGlyphCount (ctline);
3684   if (used <= glyph_len)
3685     {
3686       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3687       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3688       CGFloat total_advance = 0;
3689       CFIndex total_glyph_count = 0;
3691       for (k = 0; k < ctrun_count; k++)
3692         {
3693           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3694           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3695           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3696           CFRange string_range, comp_range, range;
3697           CFIndex *permutation;
3699           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3700             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3701           else
3702             permutation = NULL;
3704 #define RIGHT_TO_LEFT_P permutation
3706           /* Now the `comp_range' member of struct mac_glyph_layout is
3707              temporarily used as a work area such that:
3708              glbuf[i].comp_range.location =
3709              min {compRange[i + 1].location, ...,
3710                      compRange[glyph_count - 1].location,
3711                      maxRange (stringRangeForCTRun)}
3712              glbuf[i].comp_range.length = maxRange (compRange[i])
3713              where compRange[i] is the range of composed characters
3714              containing i-th glyph.  */
3715           string_range = CTRunGetStringRange (ctrun);
3716           min_location = string_range.location + string_range.length;
3717           for (i = 0; i < glyph_count; i++)
3718             {
3719               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3720               CFIndex glyph_index;
3721               CFRange rng;
3723               if (!RIGHT_TO_LEFT_P)
3724                 glyph_index = glyph_count - i - 1;
3725               else
3726                 glyph_index = i;
3727               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3728                                      &gl->string_index);
3729               rng =
3730                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3731                                                              gl->string_index);
3732               gl->comp_range.location = min_location;
3733               gl->comp_range.length = rng.location + rng.length;
3734               if (rng.location < min_location)
3735                 min_location = rng.location;
3736             }
3738           /* Fill the `comp_range' member of struct mac_glyph_layout,
3739              and setup a permutation for right-to-left text.  */
3740           comp_range = CFRangeMake (string_range.location, 0);
3741           range = CFRangeMake (0, 0);
3742           while (1)
3743             {
3744               struct mac_glyph_layout *gl =
3745                 glbuf + range.location + range.length;
3747               if (gl->comp_range.length
3748                   > comp_range.location + comp_range.length)
3749                 comp_range.length = gl->comp_range.length - comp_range.location;
3750               min_location = gl->comp_range.location;
3751               range.length++;
3753               if (min_location >= comp_range.location + comp_range.length)
3754                 {
3755                   comp_range.length = min_location - comp_range.location;
3756                   for (i = 0; i < range.length; i++)
3757                     {
3758                       glbuf[range.location + i].comp_range = comp_range;
3759                       if (RIGHT_TO_LEFT_P)
3760                         permutation[range.location + i] =
3761                           range.location + range.length - i - 1;
3762                     }
3764                   comp_range = CFRangeMake (min_location, 0);
3765                   range.location += range.length;
3766                   range.length = 0;
3767                   if (range.location == glyph_count)
3768                     break;
3769                 }
3770             }
3772           /* Then fill the remaining members.  */
3773           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3774                range.location++)
3775             {
3776               struct mac_glyph_layout *gl;
3777               CGPoint position;
3779               if (!RIGHT_TO_LEFT_P)
3780                 gl = glbuf + range.location;
3781               else
3782                 {
3783                   CFIndex src, dest;
3785                   src = glyph_count - 1 - range.location;
3786                   dest = permutation[src];
3787                   gl = glbuf + dest;
3788                   if (src < dest)
3789                     {
3790                       CFIndex tmp = gl->string_index;
3792                       gl->string_index = glbuf[src].string_index;
3793                       glbuf[src].string_index = tmp;
3794                     }
3795                 }
3796               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3798               CTRunGetPositions (ctrun, range, &position);
3799               gl->advance_delta = position.x - total_advance;
3800               gl->baseline_delta = position.y;
3801               gl->advance = (gl->advance_delta
3802                              + CTRunGetTypographicBounds (ctrun, range,
3803                                                           NULL, NULL, NULL));
3804               total_advance += gl->advance;
3805             }
3807           if (RIGHT_TO_LEFT_P)
3808             xfree (permutation);
3810 #undef RIGHT_TO_LEFT_P
3812           total_glyph_count += glyph_count;
3813         }
3815       result = used;
3816     }
3817   CFRelease (ctline);
3819   return result;
3822 /* The function below seems to cause a memory leak for the CFString
3823    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3824    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3825 #if USE_CT_GLYPH_INFO
3826 static CGGlyph
3827 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3828                               CGFontIndex cid)
3830   CGGlyph result = kCGFontIndexInvalid;
3831   UniChar characters[] = {0xfffd};
3832   CFStringRef string;
3833   CFAttributedStringRef attr_string = NULL;
3834   CTLineRef ctline = NULL;
3836   string = CFStringCreateWithCharacters (NULL, characters,
3837                                          ARRAYELTS (characters));
3839   if (string)
3840     {
3841       CTGlyphInfoRef glyph_info =
3842         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3843       CFDictionaryRef attributes = NULL;
3845       if (glyph_info)
3846         {
3847           CFStringRef keys[] = {kCTFontAttributeName,
3848                                 kCTGlyphInfoAttributeName};
3849           CFTypeRef values[] = {font, glyph_info};
3851           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3852                                            (const void **) values,
3853                                            ARRAYELTS (keys),
3854                                            &kCFTypeDictionaryKeyCallBacks,
3855                                            &kCFTypeDictionaryValueCallBacks);
3856           CFRelease (glyph_info);
3857         }
3858       if (attributes)
3859         {
3860           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3861           CFRelease (attributes);
3862         }
3863       CFRelease (string);
3864     }
3865   if (attr_string)
3866     {
3867       ctline = CTLineCreateWithAttributedString (attr_string);
3868       CFRelease (attr_string);
3869     }
3870   if (ctline)
3871     {
3872       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3874       if (CFArrayGetCount (runs) > 0)
3875         {
3876           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3877           CFDictionaryRef attributes = CTRunGetAttributes (run);
3879           if (attributes)
3880             {
3881               CTFontRef font_in_run =
3882                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3884               if (font_in_run
3885                   && mac_font_equal_in_postscript_name (font_in_run, font))
3886                 {
3887                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3888                   if (result >= CTFontGetGlyphCount (font))
3889                     result = kCGFontIndexInvalid;
3890                 }
3891             }
3892         }
3893       CFRelease (ctline);
3894     }
3896   return result;
3898 #endif
3900 static CFArrayRef
3901 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3903   CFArrayRef result = NULL;
3905 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3906 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3907   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3908 #endif
3909     {
3910       CTFontRef user_font =
3911         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3913       if (user_font)
3914         {
3915           CFArrayRef languages =
3916             CFArrayCreate (NULL, (const void **) &language, 1,
3917                            &kCFTypeArrayCallBacks);
3919           if (languages)
3920             {
3921               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3922                                                                  languages);
3923               CFRelease (languages);
3924             }
3925           CFRelease (user_font);
3926         }
3927     }
3928 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3929   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3930 #endif
3931 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3932 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3933     {
3934       CFIndex i;
3936       for (i = 0; macfont_language_default_font_names[i].language; i++)
3937         {
3938           if (CFEqual (macfont_language_default_font_names[i].language,
3939                        language))
3940             {
3941               CFMutableArrayRef descriptors =
3942                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3944               if (descriptors)
3945                 {
3946                   CFIndex j;
3948                   for (j = 0;
3949                        macfont_language_default_font_names[i].font_names[j];
3950                        j++)
3951                     {
3952                       CFDictionaryRef attributes =
3953                         CFDictionaryCreate (NULL,
3954                                             ((const void **)
3955                                              &kCTFontNameAttribute),
3956                                             ((const void **)
3957                                              &macfont_language_default_font_names[i].font_names[j]),
3958                                             1, &kCFTypeDictionaryKeyCallBacks,
3959                                             &kCFTypeDictionaryValueCallBacks);
3961                       if (attributes)
3962                         {
3963                           CTFontDescriptorRef pat_desc =
3964                             CTFontDescriptorCreateWithAttributes (attributes);
3966                           if (pat_desc)
3967                             {
3968                               CTFontDescriptorRef descriptor =
3969                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3971                               if (descriptor)
3972                                 {
3973                                   CFArrayAppendValue (descriptors, descriptor);
3974                                   CFRelease (descriptor);
3975                                 }
3976                               CFRelease (pat_desc);
3977                             }
3978                           CFRelease (attributes);
3979                         }
3980                     }
3981                   result = descriptors;
3982                 }
3983               break;
3984             }
3985         }
3986     }
3987 #endif
3989   return result;
3992 static CFStringRef
3993 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3994                                                       CFArrayRef languages)
3996   CFStringRef result = NULL;
3997   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3998   CFArrayRef descriptors =
3999     mac_font_copy_default_descriptors_for_language (language);
4001   if (descriptors)
4002     {
4003       CFIndex i, count = CFArrayGetCount (descriptors);
4005       for (i = 0; i < count; i++)
4006         {
4007           CTFontDescriptorRef descriptor =
4008             CFArrayGetValueAtIndex (descriptors, i);
4010           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4011                                                         Qnil, languages))
4012             {
4013               CFStringRef family =
4014                 CTFontDescriptorCopyAttribute (descriptor,
4015                                                kCTFontFamilyNameAttribute);
4016               if (family)
4017                 {
4018                   if (!CFStringHasPrefix (family, CFSTR ("."))
4019                       && !CFEqual (family, CFSTR ("LastResort")))
4020                     {
4021                       result = family;
4022                       break;
4023                     }
4024                   else
4025                     CFRelease (family);
4026                 }
4027             }
4028         }
4029       CFRelease (descriptors);
4030     }
4032   return result;
4035 void *
4036 macfont_get_nsctfont (struct font *font)
4038   struct macfont_info *macfont_info = (struct macfont_info *) font;
4039   CTFontRef macfont = macfont_info->macfont;
4041   return (void *) macfont;
4044 void
4045 mac_register_font_driver (struct frame *f)
4047   register_font_driver (&macfont_driver, f);
4051 void
4052 syms_of_macfont (void)
4054   /* Core Text, for Mac OS X.  */
4055   DEFSYM (Qmac_ct, "mac-ct");
4056   macfont_driver.type = Qmac_ct;
4057   register_font_driver (&macfont_driver, NULL);
4059   /* The font property key specifying the font design destination.  The
4060      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4061      text.  (See the documentation of X Logical Font Description
4062      Conventions.)  In the Mac font driver, 1 means the screen font is
4063      used for calculating some glyph metrics.  You can see the
4064      difference with Monaco 8pt or 9pt, for example.  */
4065   DEFSYM (QCdestination, ":destination");
4067   /* The boolean-valued font property key specifying the use of leading.  */
4068   DEFSYM (QCminspace, ":minspace");
4070   macfont_family_cache = Qnil;
4071   staticpro (&macfont_family_cache);