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