1 /* Font driver on macOS Core text.
2 Copyright (C) 2009-2017 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or (at
9 your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
25 #include "dispextern.h"
27 #include "blockinput.h"
28 #include "character.h"
30 #include "composite.h"
39 #include <libkern/OSByteOrder.h>
41 static double mac_font_get_advance_width_for_glyph (CTFontRef, CGGlyph);
42 static CGRect mac_font_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
43 static CFArrayRef mac_font_create_available_families (void);
44 static Boolean mac_font_equal_in_postscript_name (CTFontRef, CTFontRef);
45 static CTLineRef mac_font_create_line_with_string_and_font (CFStringRef,
47 static Boolean mac_font_descriptor_supports_languages (CTFontDescriptorRef,
49 static CFStringRef mac_font_create_preferred_family_for_attributes (CFDictionaryRef);
50 static CFIndex mac_font_shape (CTFontRef, CFStringRef,
51 struct mac_glyph_layout *, CFIndex);
52 static CFArrayRef mac_font_copy_default_descriptors_for_language (CFStringRef);
53 static CFStringRef mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef, CFArrayRef);
55 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef, CTCharacterCollection,
59 struct macfont_metrics;
61 /* The actual structure for Mac font that can be cast to struct font. */
68 ScreenFontRef screen_font;
69 struct macfont_cache *cache;
70 struct macfont_metrics **metrics;
72 bool_bf synthetic_italic_p : 1;
73 bool_bf synthetic_bold_p : 1;
75 unsigned antialias : 2;
76 bool_bf color_bitmap_p : 1;
79 /* Values for the `spacing' member in `struct macfont_info'. */
83 MACFONT_SPACING_PROPORTIONAL,
85 MACFONT_SPACING_SYNTHETIC_MONO,
88 /* Values for the `antialias' member in `struct macfont_info'. */
92 MACFONT_ANTIALIAS_DEFAULT,
93 MACFONT_ANTIALIAS_OFF,
97 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
98 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200}; /* FC_WEIGHT_BOLD */
99 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
101 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
102 static const CGFloat synthetic_bold_factor = 0.024;
104 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
105 CTFontSymbolicTraits *);
106 static void macfont_store_descriptor_attributes (CTFontDescriptorRef,
108 static Lisp_Object macfont_descriptor_entity (CTFontDescriptorRef, Lisp_Object,
109 CTFontSymbolicTraits);
110 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
111 static int macfont_glyph_extents (struct font *, CGGlyph,
112 struct font_metrics *, CGFloat *, int);
113 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
114 static Boolean macfont_supports_charset_and_languages_p (CTFontDescriptorRef,
118 static Boolean macfont_closest_traits_index_p (CFArrayRef, CTFontSymbolicTraits,
120 static CFDataRef mac_font_copy_uvs_table (CTFontRef);
121 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
123 CGGlyph [], CFIndex);
125 /* From CFData to a lisp string. Always returns a unibyte string. */
128 cfdata_to_lisp (CFDataRef data)
130 CFIndex len = CFDataGetLength (data);
131 Lisp_Object result = make_uninit_string (len);
133 CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
140 /* From CFString to a lisp string. Returns a unibyte string
141 containing a UTF-8 byte sequence. */
144 cfstring_to_lisp_nodecode (CFStringRef string)
146 Lisp_Object result = Qnil;
148 const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
152 CFIndex i, length = CFStringGetLength (string);
154 for (i = 0; i < length; i++)
155 if (CFStringGetCharacterAtIndex (string, i) == 0)
159 return make_unibyte_string (s, strlen (s));
162 data = CFStringCreateExternalRepresentation (NULL, string,
163 kCFStringEncodingUTF8, '?');
166 result = cfdata_to_lisp (data);
173 /* Lisp string containing a UTF-8 byte sequence to CFString. Unlike
174 cfstring_create_with_utf8_cstring, this function preserves NUL
178 cfstring_create_with_string_noencode (Lisp_Object s)
180 CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
181 kCFStringEncodingUTF8, false);
184 /* Failed to interpret as UTF 8. Fall back on Mac Roman. */
185 string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
186 kCFStringEncodingMacRoman, false);
192 mac_font_get_weight (CTFontRef font)
194 NSFont *nsFont = (NSFont *) font;
196 return [[NSFontManager sharedFontManager] weightOfFont:nsFont];
200 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
202 NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
204 return advancement.width;
207 #if !USE_CT_GLYPH_INFO
209 mac_font_get_glyph_for_cid (CTFontRef font, NSCharacterCollection collection,
212 CGGlyph result = kCGFontIndexInvalid;
213 NSFont *nsFont = (NSFont *) font;
214 unichar characters[] = {0xfffd};
216 [NSString stringWithCharacters:characters
217 length:ARRAYELTS (characters)];
218 NSGlyphInfo *glyphInfo =
219 [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
220 collection:collection
222 NSDictionary *attributes =
223 [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
224 glyphInfo,NSGlyphInfoAttributeName,nil];
225 NSTextStorage *textStorage =
226 [[NSTextStorage alloc] initWithString:string
227 attributes:attributes];
228 NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
229 NSTextContainer *textContainer = [[NSTextContainer alloc] init];
230 NSFont *fontInTextStorage;
232 [layoutManager addTextContainer:textContainer];
233 [textContainer release];
234 [textStorage addLayoutManager:layoutManager];
235 [layoutManager release];
238 (void) [layoutManager glyphRangeForTextContainer:textContainer];
240 fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
241 effectiveRange:NULL];
242 if (fontInTextStorage == nsFont
243 || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
245 NSGlyph glyph = [layoutManager glyphAtIndex:0];
247 if (glyph < [nsFont numberOfGlyphs])
251 [textStorage release];
258 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
260 NSFont *result, *font;
262 font = [NSFont fontWithName:((NSString *) name) size:size];
263 result = [font screenFont];
265 return (ScreenFontRef)[result retain];
270 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
271 CGFloat *descent, CGFloat *leading)
273 NSFont *nsFont = [(NSFont *)font printerFont];
274 NSTextStorage *textStorage;
275 NSLayoutManager *layoutManager;
276 NSTextContainer *textContainer;
278 NSPoint spaceLocation;
281 textStorage = [[NSTextStorage alloc] initWithString:@" "];
282 layoutManager = [[NSLayoutManager alloc] init];
283 textContainer = [[NSTextContainer alloc] init];
285 [textStorage setFont:nsFont];
286 [textContainer setLineFragmentPadding:0];
288 [layoutManager addTextContainer:textContainer];
289 [textContainer release];
290 [textStorage addLayoutManager:layoutManager];
291 [layoutManager release];
293 if (!(textStorage && layoutManager && textContainer))
295 [textStorage release];
300 usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
301 effectiveRange:NULL];
302 spaceLocation = [layoutManager locationForGlyphAtIndex:0];
303 [textStorage release];
305 *ascent = spaceLocation.y;
306 *descent = NSHeight (usedRect) - spaceLocation.y;
308 descender = [nsFont descender];
309 if (- descender < *descent)
311 *leading = *descent + descender;
312 *descent = - descender;
319 mac_font_shape_1 (NSFont *font, NSString *string,
320 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
324 NSTextStorage *textStorage;
325 NSLayoutManager *layoutManager;
326 NSTextContainer *textContainer;
327 NSUInteger stringLength;
328 NSPoint spaceLocation;
329 NSUInteger used, numberOfGlyphs;
331 textStorage = [[NSTextStorage alloc] initWithString:string];
332 layoutManager = [[NSLayoutManager alloc] init];
333 textContainer = [[NSTextContainer alloc] init];
335 /* Append a trailing space to measure baseline position. */
336 [textStorage appendAttributedString:([[[NSAttributedString alloc]
337 initWithString:@" "] autorelease])];
338 [textStorage setFont:font];
339 [textContainer setLineFragmentPadding:0];
341 [layoutManager addTextContainer:textContainer];
342 [textContainer release];
343 [textStorage addLayoutManager:layoutManager];
344 [layoutManager release];
346 if (!(textStorage && layoutManager && textContainer))
348 [textStorage release];
353 stringLength = [string length];
356 (void) [layoutManager glyphRangeForTextContainer:textContainer];
358 spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
360 /* Remove the appended trailing space because otherwise it may
361 generate a wrong result for a right-to-left text. */
362 [textStorage beginEditing];
363 [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
364 [textStorage endEditing];
365 (void) [layoutManager glyphRangeForTextContainer:textContainer];
368 while (i < stringLength)
371 NSFont *fontInTextStorage =
372 [textStorage attribute:NSFontAttributeName atIndex:i
373 longestEffectiveRange:&range
374 inRange:(NSMakeRange (0, stringLength))];
376 if (!(fontInTextStorage == font
377 || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
379 i = NSMaxRange (range);
381 if (i < stringLength)
382 /* Make the test `used <= glyph_len' below fail if textStorage
383 contained some fonts other than the specified one. */
384 used = glyph_len + 1;
387 NSRange range = NSMakeRange (0, stringLength);
389 range = [layoutManager glyphRangeForCharacterRange:range
390 actualCharacterRange:NULL];
391 numberOfGlyphs = NSMaxRange (range);
392 used = numberOfGlyphs;
393 for (i = 0; i < numberOfGlyphs; i++)
394 if ([layoutManager notShownAttributeForGlyphAtIndex:i])
398 if (0 < used && used <= glyph_len)
400 NSUInteger glyphIndex, prevGlyphIndex;
401 unsigned char bidiLevel;
402 NSUInteger *permutation;
403 NSRange compRange, range;
404 CGFloat totalAdvance;
407 while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
410 /* For now we assume the direction is not changed within the
412 [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
415 characterIndexes:NULL
416 bidiLevels:&bidiLevel];
418 permutation = xmalloc (sizeof (NSUInteger) * used);
422 #define RIGHT_TO_LEFT_P permutation
424 /* Fill the `comp_range' member of struct mac_glyph_layout, and
425 setup a permutation for right-to-left text. */
426 compRange = NSMakeRange (0, 0);
427 for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
430 struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
431 NSUInteger characterIndex =
432 [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
434 gl->string_index = characterIndex;
436 if (characterIndex >= NSMaxRange (compRange))
438 compRange.location = NSMaxRange (compRange);
441 NSRange characterRange =
443 rangeOfComposedCharacterSequenceAtIndex:characterIndex];
446 NSMaxRange (characterRange) - compRange.location;
447 [layoutManager glyphRangeForCharacterRange:compRange
448 actualCharacterRange:&characterRange];
449 characterIndex = NSMaxRange (characterRange) - 1;
451 while (characterIndex >= NSMaxRange (compRange));
454 for (i = 0; i < range.length; i++)
455 permutation[range.location + i] = NSMaxRange (range) - i - 1;
457 range = NSMakeRange (NSMaxRange (range), 0);
460 gl->comp_range.location = compRange.location;
461 gl->comp_range.length = compRange.length;
463 while (++glyphIndex < numberOfGlyphs)
464 if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
468 for (i = 0; i < range.length; i++)
469 permutation[range.location + i] = NSMaxRange (range) - i - 1;
471 /* Then fill the remaining members. */
472 glyphIndex = prevGlyphIndex = 0;
473 while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
476 if (!RIGHT_TO_LEFT_P)
483 rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
484 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
485 inTextContainer:textContainer rectCount:&nrects];
487 totalAdvance = NSMaxX (glyphRects[0]);
490 for (i = 0; i < used; i++)
492 struct mac_glyph_layout *gl;
494 NSUInteger nextGlyphIndex;
499 if (!RIGHT_TO_LEFT_P)
500 gl = glyph_layouts + i;
503 NSUInteger dest = permutation[i];
505 gl = glyph_layouts + dest;
508 CFIndex tmp = gl->string_index;
510 gl->string_index = glyph_layouts[i].string_index;
511 glyph_layouts[i].string_index = tmp;
514 gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
516 location = [layoutManager locationForGlyphAtIndex:glyphIndex];
517 gl->baseline_delta = spaceLocation.y - location.y;
519 for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
522 notShownAttributeForGlyphAtIndex:nextGlyphIndex])
525 if (!RIGHT_TO_LEFT_P)
529 if (prevGlyphIndex == 0)
530 glyphRange = NSMakeRange (0, nextGlyphIndex);
532 glyphRange = NSMakeRange (glyphIndex,
533 nextGlyphIndex - glyphIndex);
536 rectArrayForGlyphRange:glyphRange
537 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
538 inTextContainer:textContainer rectCount:&nrects];
539 maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
540 gl->advance_delta = location.x - totalAdvance;
541 gl->advance = maxX - totalAdvance;
548 if (nextGlyphIndex == numberOfGlyphs)
549 glyphRange = NSMakeRange (prevGlyphIndex,
550 numberOfGlyphs - prevGlyphIndex);
552 glyphRange = NSMakeRange (prevGlyphIndex,
553 glyphIndex + 1 - prevGlyphIndex);
556 rectArrayForGlyphRange:glyphRange
557 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
558 inTextContainer:textContainer rectCount:&nrects];
559 minX = min (NSMinX (glyphRects[0]), totalAdvance);
560 gl->advance = totalAdvance - minX;
562 gl->advance_delta = location.x - totalAdvance;
565 prevGlyphIndex = glyphIndex + 1;
566 glyphIndex = nextGlyphIndex;
572 #undef RIGHT_TO_LEFT_P
576 [textStorage release];
582 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
583 struct mac_glyph_layout *glyph_layouts,
586 return mac_font_shape_1 ([(NSFont *)font printerFont],
588 glyph_layouts, glyph_len);
592 get_cgcolor(unsigned long idx, struct frame *f)
594 NSColor *nsColor = ns_lookup_indexed_color (idx, f);
596 CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
597 NSInteger noc = [nsColor numberOfComponents];
598 CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
601 [nsColor getComponents: components];
602 cgColor = CGColorCreate (colorSpace, components);
607 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f) \
609 CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \
610 CGContextSetFillColorWithColor (context, refcol_) ; \
611 CGColorRelease (refcol_); \
613 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f) \
615 CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f); \
616 CGContextSetFillColorWithColor (context, refcol_); \
617 CGColorRelease (refcol_); \
619 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f) \
621 CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f); \
622 CGContextSetStrokeColorWithColor (context, refcol_); \
623 CGColorRelease (refcol_); \
628 /* Mac font driver. */
634 /* characters to distinguish the charset from the others */
636 /* additional constraint by language */
639 CFCharacterSetRef cf_charset;
640 CFStringRef cf_charset_string;
641 } cf_charset_table[] =
642 { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
643 { "iso8859-2", { 0x00A0, 0x010E }},
644 { "iso8859-3", { 0x00A0, 0x0108 }},
645 { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
646 { "iso8859-5", { 0x00A0, 0x0401 }},
647 { "iso8859-6", { 0x00A0, 0x060C }},
648 { "iso8859-7", { 0x00A0, 0x0384 }},
649 { "iso8859-8", { 0x00A0, 0x05D0 }},
650 { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
651 { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
652 { "iso8859-11", { 0x00A0, 0x0E01 }},
653 { "iso8859-13", { 0x00A0, 0x201C }},
654 { "iso8859-14", { 0x00A0, 0x0174 }},
655 { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
656 { "iso8859-16", { 0x00A0, 0x0218}},
657 { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
658 { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
659 { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
660 { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
661 { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
662 { "cns11643.1992-2", { 0x4E33, 0x7934 }},
663 { "cns11643.1992-3", { 0x201A9 }},
664 { "cns11643.1992-4", { 0x20057 }},
665 { "cns11643.1992-5", { 0x20000 }},
666 { "cns11643.1992-6", { 0x20003 }},
667 { "cns11643.1992-7", { 0x20055 }},
668 { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
669 { "jisx0212.1990-0", { 0x4E44 }},
670 { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
671 { "jisx0213.2000-2", { 0xFA49 }},
672 { "jisx0213.2004-1", { 0x20B9F }},
673 { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
674 { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
675 { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
676 { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
677 { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
678 { "unicode-sip", { 0x20000 }},
682 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
685 CFStringRef language;
686 CFStringRef font_names[3];
687 } macfont_language_default_font_names[] = {
688 { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
689 CFSTR ("HiraKakuPro-W3"), /* 10.4 */
691 { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
692 CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
694 { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
695 CFSTR ("STXihei"), /* 10.4 - 10.5 */
697 { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
698 CFSTR ("LiHeiPro"), /* 10.4 - 10.5 */
704 static CGFloat macfont_antialias_threshold;
707 macfont_update_antialias_threshold (void)
713 CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
714 kCFPreferencesCurrentApplication,
717 macfont_antialias_threshold = threshold;
720 static inline Lisp_Object
721 macfont_intern_prop_cfstring (CFStringRef cfstring)
723 Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
725 return font_intern_prop (SSDATA (string), SBYTES (string), 1);
728 static inline CFIndex
729 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
740 unichars[0] = (c >> 10) + 0xD800;
741 unichars[1] = (c & 0x3FF) + 0xDC00;
748 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
749 CTFontSymbolicTraits *sym_traits)
753 /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
754 OS X 10.6 when the value is greater than or equal to 1 << 31. */
755 if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
757 *sym_traits = (CTFontSymbolicTraits) sint64_value;
766 mac_font_descriptor_get_adjusted_weight (CTFontDescriptorRef desc, CGFloat val)
768 long percent_val = lround (val * 100);
770 if (percent_val == -40)
772 CTFontRef font = NULL;
774 CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
778 font = CTFontCreateWithName (name, 0, NULL);
783 CFIndex weight = mac_font_get_weight (font);
785 /* Workaround for crash when displaying Oriya characters
786 with Arial Unicode MS on OS X 10.11. */
797 macfont_store_descriptor_attributes (CTFontDescriptorRef desc,
798 Lisp_Object spec_or_entity)
801 CFDictionaryRef dict;
805 str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
808 ASET (spec_or_entity, FONT_FAMILY_INDEX,
809 macfont_intern_prop_cfstring (str));
812 dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
816 enum font_property_index index;
819 CGFloat (*adjust_func) (CTFontDescriptorRef, CGFloat);
821 {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
822 {{-0.4, 50}, /* light */
823 {-0.24, 87.5}, /* (semi-light + normal) / 2 */
824 {0, 100}, /* normal */
825 {0.24, 140}, /* (semi-bold + normal) / 2 */
826 {0.4, 200}, /* bold */
827 {CGFLOAT_MAX, CGFLOAT_MAX}},
828 mac_font_descriptor_get_adjusted_weight},
829 {FONT_SLANT_INDEX, kCTFontSlantTrait,
830 {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL},
831 {FONT_WIDTH_INDEX, kCTFontWidthTrait,
832 {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL}};
835 for (i = 0; i < ARRAYELTS (numeric_traits); i++)
837 num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
838 if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
840 CGPoint *point = numeric_traits[i].points;
842 if (numeric_traits[i].adjust_func)
843 floatval = (*numeric_traits[i].adjust_func) (desc, floatval);
844 while (point->x < floatval)
846 if (point == numeric_traits[i].points)
848 else if (point->x == CGFLOAT_MAX)
850 floatval = (point - 1)->y + ((floatval - (point - 1)->x)
851 * ((point->y - (point - 1)->y)
852 / (point->x - (point - 1)->x)));
853 FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
854 make_number (lround (floatval)));
858 num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
861 CTFontSymbolicTraits sym_traits;
864 cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
865 spacing = (sym_traits & kCTFontTraitMonoSpace
866 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
867 ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
872 num = CTFontDescriptorCopyAttribute (desc, kCTFontSizeAttribute);
873 if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
874 ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
876 ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
882 macfont_descriptor_entity (CTFontDescriptorRef desc, Lisp_Object extra,
883 CTFontSymbolicTraits synth_sym_traits)
886 CFDictionaryRef dict;
887 CTFontSymbolicTraits sym_traits = 0;
890 entity = font_make_entity ();
892 ASET (entity, FONT_TYPE_INDEX, Qmac_ct);
893 ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
895 macfont_store_descriptor_attributes (desc, entity);
897 dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
900 CFNumberRef num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
903 cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
906 if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
907 ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
908 ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
909 name = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
910 font_put_extra (entity, QCfont_entity,
911 make_save_ptr_int ((void *) name, sym_traits));
912 if (synth_sym_traits & kCTFontTraitItalic)
913 FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
914 make_number (FONT_SLANT_SYNTHETIC_ITALIC));
915 if (synth_sym_traits & kCTFontTraitBold)
916 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
917 make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
918 if (synth_sym_traits & kCTFontTraitMonoSpace)
919 ASET (entity, FONT_SPACING_INDEX,
920 make_number (FONT_SPACING_SYNTHETIC_MONO));
925 /* Cache for font family name symbols vs CFStrings. A value of nil
926 means the cache has been invalidated. Otherwise the value is a Lisp
927 hash table whose keys are symbols and the value for a key is either
928 nil (no corresponding family name) or a Lisp save value wrapping the
929 corresponding family name in CFString. */
931 static Lisp_Object macfont_family_cache;
934 macfont_invalidate_family_cache (void)
936 if (HASH_TABLE_P (macfont_family_cache))
938 struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
939 ptrdiff_t i, size = HASH_TABLE_SIZE (h);
941 for (i = 0; i < size; ++i)
942 if (!NILP (HASH_HASH (h, i)))
944 Lisp_Object value = HASH_VALUE (h, i);
946 if (SAVE_VALUEP (value))
947 CFRelease (XSAVE_POINTER (value, 0));
949 macfont_family_cache = Qnil;
954 macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
956 if (HASH_TABLE_P (macfont_family_cache))
958 struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
959 ptrdiff_t i = hash_lookup (h, symbol, NULL);
963 Lisp_Object value = HASH_VALUE (h, i);
965 *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
975 macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
977 struct Lisp_Hash_Table *h;
982 if (!HASH_TABLE_P (macfont_family_cache))
983 macfont_family_cache = CALLN (Fmake_hash_table, QCtest, Qeq);
985 h = XHASH_TABLE (macfont_family_cache);
986 i = hash_lookup (h, symbol, &hash);
987 value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
990 Lisp_Object old_value = HASH_VALUE (h, i);
992 if (SAVE_VALUEP (old_value))
993 CFRelease (XSAVE_POINTER (old_value, 0));
994 set_hash_value_slot (h, i, value);
997 hash_put (h, symbol, value, hash);
1000 /* Cache of all the available font family names except "LastResort"
1001 and those start with ".". NULL means the cache has been invalidated.
1002 Otherwise, the value is CFArray of CFStrings and the elements are
1003 sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
1004 Mac OS X 10.6 and later). */
1006 static CFArrayRef macfont_available_families_cache = NULL;
1009 macfont_invalidate_available_families_cache (void)
1011 if (macfont_available_families_cache)
1013 CFRelease (macfont_available_families_cache);
1014 macfont_available_families_cache = NULL;
1019 macfont_handle_font_change_notification (CFNotificationCenterRef center,
1021 CFStringRef name, const void *object,
1022 CFDictionaryRef userInfo)
1024 macfont_invalidate_family_cache ();
1025 macfont_invalidate_available_families_cache ();
1029 macfont_init_font_change_handler (void)
1031 static bool initialized = false;
1037 CFNotificationCenterAddObserver
1038 (CFNotificationCenterGetLocalCenter (), NULL,
1039 macfont_handle_font_change_notification,
1040 kCTFontManagerRegisteredFontsChangedNotification,
1041 NULL, CFNotificationSuspensionBehaviorCoalesce);
1045 macfont_copy_available_families_cache (void)
1047 macfont_init_font_change_handler ();
1049 if (macfont_available_families_cache == NULL)
1050 macfont_available_families_cache = mac_font_create_available_families ();
1052 return (macfont_available_families_cache
1053 ? CFRetain (macfont_available_families_cache) : NULL);
1057 macfont_create_family_with_symbol (Lisp_Object symbol)
1059 CFStringRef result = NULL, family_name;
1060 CFDictionaryRef attributes = NULL;
1061 CTFontDescriptorRef pat_desc = NULL;
1063 if (macfont_get_family_cache_if_present (symbol, &result))
1064 return result ? CFRetain (result) : NULL;
1066 family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1070 CFDictionaryCreate (NULL,
1071 (const void **) &kCTFontFamilyNameAttribute,
1072 (const void **) &family_name, 1,
1073 &kCFTypeDictionaryKeyCallBacks,
1074 &kCFTypeDictionaryValueCallBacks);
1075 CFRelease (family_name);
1079 pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
1080 CFRelease (attributes);
1084 CTFontDescriptorRef desc =
1085 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
1090 CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
1093 macfont_set_family_cache (symbol, result);
1094 CFRelease (pat_desc);
1100 #define WIDTH_FRAC_BITS (4)
1101 #define WIDTH_FRAC_SCALE (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1103 struct macfont_metrics
1105 unsigned char lbearing_low, rbearing_low;
1106 signed lbearing_high : 4, rbearing_high : 4;
1107 unsigned char ascent_low, descent_low;
1108 signed ascent_high : 4, descent_high : 4;
1110 /* These two members are used for fixed-point representation of
1111 glyph width. The `width_int' member is an integer that is
1112 closest to the width. The `width_frac' member is the fractional
1113 adjustment representing a value in [-.5, .5], multiplied by
1114 WIDTH_FRAC_SCALE. For synthetic monospace fonts, they represent
1115 the advance delta for centering instead of the glyph width. */
1116 signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1119 #define METRICS_VALUE(metrics, member) \
1120 (((metrics)->member##_high << 8) | (metrics)->member##_low)
1121 #define METRICS_SET_VALUE(metrics, member, value) \
1122 do {short tmp = (value); (metrics)->member##_low = tmp & 0xff; \
1123 (metrics)->member##_high = tmp >> 8;} while (0)
1127 METRICS_INVALID = -1, /* metrics entry is invalid */
1128 METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1131 #define METRICS_STATUS(metrics) \
1132 (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1133 #define METRICS_SET_STATUS(metrics, status) \
1134 do {METRICS_SET_VALUE (metrics, ascent, 0); \
1135 METRICS_SET_VALUE (metrics, descent, status);} while (0)
1137 #define METRICS_NCOLS_PER_ROW (128)
1138 #define LCD_FONT_SMOOTHING_LEFT_MARGIN (0.396f)
1139 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1142 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1143 struct font_metrics *metrics, CGFloat *advance_delta,
1144 int force_integral_p)
1146 struct macfont_info *macfont_info = (struct macfont_info *) font;
1147 CTFontRef macfont = macfont_info->macfont;
1149 struct macfont_metrics *cache;
1152 row = glyph / METRICS_NCOLS_PER_ROW;
1153 col = glyph % METRICS_NCOLS_PER_ROW;
1154 if (row >= macfont_info->metrics_nrows)
1156 macfont_info->metrics =
1157 xrealloc (macfont_info->metrics,
1158 sizeof (struct macfont_metrics *) * (row + 1));
1159 memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1160 (sizeof (struct macfont_metrics *)
1161 * (row + 1 - macfont_info->metrics_nrows)));
1162 macfont_info->metrics_nrows = row + 1;
1164 if (macfont_info->metrics[row] == NULL)
1166 struct macfont_metrics *new;
1169 new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1170 for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1171 METRICS_SET_STATUS (new + i, METRICS_INVALID);
1172 macfont_info->metrics[row] = new;
1174 cache = macfont_info->metrics[row] + col;
1176 if (METRICS_STATUS (cache) == METRICS_INVALID)
1180 if (macfont_info->screen_font)
1181 fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1183 fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1185 /* For synthetic mono fonts, cache->width_{int,frac} holds the
1186 advance delta value. */
1187 if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1188 fwidth = (font->pixel_size - fwidth) / 2;
1189 cache->width_int = lround (fwidth);
1190 cache->width_frac = lround ((fwidth - cache->width_int)
1191 * WIDTH_FRAC_SCALE);
1192 METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1194 if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1195 width = font->pixel_size;
1197 width = cache->width_int;
1201 if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1203 CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1205 if (macfont_info->synthetic_italic_p)
1207 /* We assume the members a, b, c, and d in
1208 synthetic_italic_atfm are non-negative. */
1210 CGPointApplyAffineTransform (bounds.origin,
1211 synthetic_italic_atfm);
1213 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1215 if (macfont_info->synthetic_bold_p && ! force_integral_p)
1217 CGFloat d = - synthetic_bold_factor * CTFontGetSize (macfont) / 2;
1219 bounds = CGRectInset (bounds, d, d);
1221 switch (macfont_info->spacing)
1223 case MACFONT_SPACING_PROPORTIONAL:
1224 bounds.origin.x += - (cache->width_frac
1225 / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1227 case MACFONT_SPACING_MONO:
1229 case MACFONT_SPACING_SYNTHETIC_MONO:
1230 bounds.origin.x += (cache->width_int
1231 + (cache->width_frac
1232 / (CGFloat) WIDTH_FRAC_SCALE));
1235 if (bounds.size.width > 0)
1237 bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1238 bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1239 + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1241 bounds = CGRectIntegral (bounds);
1242 METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1243 METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1244 METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1245 METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1247 metrics->lbearing = METRICS_VALUE (cache, lbearing);
1248 metrics->rbearing = METRICS_VALUE (cache, rbearing);
1249 metrics->width = width;
1250 metrics->ascent = METRICS_VALUE (cache, ascent);
1251 metrics->descent = METRICS_VALUE (cache, descent);
1256 switch (macfont_info->spacing)
1258 case MACFONT_SPACING_PROPORTIONAL:
1259 *advance_delta = (force_integral_p ? 0
1260 : - (cache->width_frac
1261 / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1263 case MACFONT_SPACING_MONO:
1266 case MACFONT_SPACING_SYNTHETIC_MONO:
1267 *advance_delta = (force_integral_p ? cache->width_int
1269 + (cache->width_frac
1270 / (CGFloat) WIDTH_FRAC_SCALE)));
1278 static CFMutableDictionaryRef macfont_cache_dictionary;
1280 /* Threshold used in row_nkeys_or_perm. This must be less than or
1281 equal to the number of rows that are invalid as BMP (i.e., from
1282 U+D800 to U+DFFF). */
1283 #define ROW_PERM_OFFSET (8)
1285 /* The number of glyphs that can be stored in a value for a single
1286 entry of CFDictionary. */
1287 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1289 struct macfont_cache
1291 int reference_count;
1292 CFCharacterSetRef cf_charset;
1294 /* The cached glyph for a BMP character c is stored in
1295 matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1296 if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET. */
1297 unsigned char row_nkeys_or_perm[256];
1300 /* Number of rows for which the BMP cache is allocated so far.
1301 I.e., matrix[0] ... matrix[nrows - 1] are non-NULL. */
1304 /* The cached glyph for a character c is stored as the (c %
1305 NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1306 NGLYPHS_IN_VALUE). However, the glyph for a BMP character c is
1307 not stored here if row_nkeys_or_perm[c / 256] >=
1309 CFMutableDictionaryRef dictionary;
1313 /* UVS (Unicode Variation Sequence) subtable data, which is of
1314 type CFDataRef if available. NULL means it is not initialized
1315 yet. kCFNull means the subtable is not found and there is no
1316 suitable fallback table for this font. */
1319 /* Character collection specifying the destination of the mapping
1320 provided by `table' above. If `table' is obtained from the UVS
1321 subtable in the font cmap table, then the value of this member
1322 should be NSIdentityMappingCharacterCollection. */
1323 NSCharacterCollection collection;
1327 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1328 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1329 static void macfont_release_cache (struct macfont_cache *);
1330 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1331 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1332 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1333 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1334 NSCharacterCollection, CGFontIndex);
1335 static CFDataRef macfont_get_uvs_table (struct font *, NSCharacterCollection *);
1337 static struct macfont_cache *
1338 macfont_lookup_cache (CFStringRef key)
1340 struct macfont_cache *cache;
1342 if (macfont_cache_dictionary == NULL)
1344 macfont_cache_dictionary =
1345 CFDictionaryCreateMutable (NULL, 0,
1346 &kCFTypeDictionaryKeyCallBacks, NULL);
1350 cache = ((struct macfont_cache *)
1351 CFDictionaryGetValue (macfont_cache_dictionary, key));
1355 CTFontRef macfont = CTFontCreateWithName (key, 0, NULL);
1359 cache = xzalloc (sizeof (struct macfont_cache));
1360 /* Treat the LastResort font as if it contained glyphs for
1361 all characters. This may look too rough, but neither
1362 CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1363 for this font is correct for non-BMP characters on Mac OS
1365 if (CFEqual (key, CFSTR ("LastResort")))
1367 CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1370 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1372 if (cache->cf_charset == NULL)
1373 cache->cf_charset = CTFontCopyCharacterSet (macfont);
1374 CFDictionaryAddValue (macfont_cache_dictionary, key,
1375 (const void *) cache);
1376 CFRelease (macfont);
1383 static struct macfont_cache *
1384 macfont_retain_cache (struct macfont_cache *cache)
1386 cache->reference_count++;
1392 macfont_release_cache (struct macfont_cache *cache)
1394 if (--cache->reference_count == 0)
1398 for (i = 0; i < cache->glyph.nrows; i++)
1399 xfree (cache->glyph.matrix[i]);
1400 xfree (cache->glyph.matrix);
1401 if (cache->glyph.dictionary)
1402 CFRelease (cache->glyph.dictionary);
1403 memset (&cache->glyph, 0, sizeof (cache->glyph));
1404 if (cache->uvs.table)
1405 CFRelease (cache->uvs.table);
1406 memset (&cache->uvs, 0, sizeof (cache->uvs));
1410 static CFCharacterSetRef
1411 macfont_get_cf_charset (struct font *font)
1413 struct macfont_info *macfont_info = (struct macfont_info *) font;
1415 return macfont_info->cache->cf_charset;
1418 static CFCharacterSetRef
1419 macfont_get_cf_charset_for_name (CFStringRef name)
1421 struct macfont_cache *cache = macfont_lookup_cache (name);
1423 return cache->cf_charset;
1427 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1429 struct macfont_info *macfont_info = (struct macfont_info *) font;
1430 CTFontRef macfont = macfont_info->macfont;
1431 struct macfont_cache *cache = macfont_info->cache;
1433 if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1436 int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1438 if (nkeys_or_perm < ROW_PERM_OFFSET)
1440 UniChar unichars[256], ch;
1444 dispatch_queue_t queue;
1445 dispatch_group_t group = NULL;
1449 CFMutableDictionaryRef dictionary;
1450 uintptr_t key, value;
1454 if (cache->glyph.dictionary == NULL)
1455 cache->glyph.dictionary =
1456 CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1457 dictionary = cache->glyph.dictionary;
1458 key = c / NGLYPHS_IN_VALUE;
1459 nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1460 value = ((uintptr_t)
1461 CFDictionaryGetValue (dictionary, (const void *) key));
1462 glyph = (value >> nshifts);
1466 if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1469 if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1471 glyph = kCGFontIndexInvalid;
1474 cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1475 value |= ((uintptr_t) glyph << nshifts);
1476 CFDictionarySetValue (dictionary, (const void *) key,
1477 (const void *) value);
1483 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1484 group = dispatch_group_create ();
1485 dispatch_group_async (group, queue, ^{
1488 nkeys = nkeys_or_perm;
1489 for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1490 if (CFDictionaryContainsKey (dictionary,
1491 (const void *) key))
1493 CFDictionaryRemoveValue (dictionary,
1494 (const void *) key);
1502 for (i = 0; i < 256; i++)
1505 if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1506 unichars[len++] = ch;
1509 glyphs = xmalloc (sizeof (CGGlyph) * 256);
1512 CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1515 int next = unichars[len - 1] % 256;
1518 glyphs[i] = kCGFontIndexInvalid;
1521 glyphs[i] = glyphs[len];
1528 glyphs[i] = kCGFontIndexInvalid;
1530 nrows = cache->glyph.nrows;
1531 nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1532 cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1534 cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1535 sizeof (CGGlyph *) * nrows);
1536 cache->glyph.matrix[nrows - 1] = glyphs;
1537 cache->glyph.nrows = nrows;
1541 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1542 dispatch_release (group);
1546 return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1550 uintptr_t key, value;
1554 if (cache->glyph.dictionary == NULL)
1555 cache->glyph.dictionary =
1556 CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1557 key = c / NGLYPHS_IN_VALUE;
1558 nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1559 value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1560 (const void *) key);
1561 glyph = (value >> nshifts);
1564 UniChar unichars[2];
1566 CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1568 if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1571 glyph = kCGFontIndexInvalid;
1573 value |= ((uintptr_t) glyph << nshifts);
1574 CFDictionarySetValue (cache->glyph.dictionary,
1575 (const void *) key, (const void *) value);
1583 macfont_get_glyph_for_cid (struct font *font, NSCharacterCollection collection,
1586 struct macfont_info *macfont_info = (struct macfont_info *) font;
1587 CTFontRef macfont = macfont_info->macfont;
1590 return mac_font_get_glyph_for_cid (macfont, collection, cid);
1594 macfont_get_uvs_table (struct font *font, NSCharacterCollection *collection)
1596 struct macfont_info *macfont_info = (struct macfont_info *) font;
1597 CTFontRef macfont = macfont_info->macfont;
1598 struct macfont_cache *cache = macfont_info->cache;
1599 CFDataRef result = NULL;
1601 if (cache->uvs.table == NULL)
1603 CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1604 NSCharacterCollection uvs_collection =
1605 NSIdentityMappingCharacterCollection;
1607 if (uvs_table == NULL
1608 && mac_font_get_glyph_for_cid (macfont,
1609 NSAdobeJapan1CharacterCollection,
1610 6480) != kCGFontIndexInvalid)
1612 /* If the glyph for U+4E55 is accessible via its CID 6480,
1613 then we use the Adobe-Japan1 UVS table, which maps a
1614 variation sequence to a CID, as a fallback. */
1615 static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1617 if (mac_uvs_table_adobe_japan1 == NULL)
1618 mac_uvs_table_adobe_japan1 =
1619 CFDataCreateWithBytesNoCopy (NULL,
1620 mac_uvs_table_adobe_japan1_bytes,
1621 sizeof (mac_uvs_table_adobe_japan1_bytes),
1623 if (mac_uvs_table_adobe_japan1)
1625 uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1626 uvs_collection = NSAdobeJapan1CharacterCollection;
1629 if (uvs_table == NULL)
1630 cache->uvs.table = kCFNull;
1632 cache->uvs.table = uvs_table;
1633 cache->uvs.collection = uvs_collection;
1636 if (cache->uvs.table != kCFNull)
1638 result = cache->uvs.table;
1639 *collection = cache->uvs.collection;
1645 static Lisp_Object macfont_get_cache (struct frame *);
1646 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1647 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1648 static Lisp_Object macfont_list_family (struct frame *);
1649 static void macfont_free_entity (Lisp_Object);
1650 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1651 static void macfont_close (struct font *);
1652 static int macfont_has_char (Lisp_Object, int);
1653 static unsigned macfont_encode_char (struct font *, int);
1654 static void macfont_text_extents (struct font *, unsigned int *, int,
1655 struct font_metrics *);
1656 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1657 static Lisp_Object macfont_shape (Lisp_Object);
1658 static int macfont_variation_glyphs (struct font *, int c,
1659 unsigned variations[256]);
1660 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1662 static struct font_driver const macfont_driver =
1664 .type = LISPSYM_INITIALLY (Qmac_ct),
1665 .get_cache = macfont_get_cache,
1666 .list = macfont_list,
1667 .match = macfont_match,
1668 .list_family = macfont_list_family,
1669 .free_entity = macfont_free_entity,
1670 .open = macfont_open,
1671 .close = macfont_close,
1672 .has_char = macfont_has_char,
1673 .encode_char = macfont_encode_char,
1674 .text_extents = macfont_text_extents,
1675 .draw = macfont_draw,
1676 .shape = macfont_shape,
1677 .get_variation_glyphs = macfont_variation_glyphs,
1678 .filter_properties = macfont_filter_properties,
1682 macfont_get_cache (struct frame * f)
1684 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1686 return (dpyinfo->name_list_element);
1690 macfont_get_charset (Lisp_Object registry)
1692 char *str = SSDATA (SYMBOL_NAME (registry));
1693 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1697 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1701 else if (str[i] == '*')
1708 regexp = make_unibyte_string (re, j);
1709 for (i = 0; cf_charset_table[i].name; i++)
1710 if (fast_c_string_match_ignore_case
1711 (regexp, cf_charset_table[i].name,
1712 strlen (cf_charset_table[i].name)) >= 0)
1714 if (! cf_charset_table[i].name)
1716 if (! cf_charset_table[i].cf_charset)
1718 int *uniquifier = cf_charset_table[i].uniquifier;
1719 UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1722 CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1726 for (j = 0; uniquifier[j]; j++)
1728 count += macfont_store_utf32char_to_unichars (uniquifier[j],
1730 CFCharacterSetAddCharactersInRange (charset,
1731 CFRangeMake (uniquifier[j], 1));
1734 string = CFStringCreateWithCharacters (NULL, unichars, count);
1737 CFRelease (charset);
1740 cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1742 CFRelease (charset);
1743 /* CFCharacterSetCreateWithCharactersInString does not handle
1744 surrogate pairs properly as of Mac OS X 10.5. */
1745 cf_charset_table[i].cf_charset_string = string;
1753 unsigned int script_tag, langsys_tag;
1755 unsigned int *features[2];
1758 #define OTF_SYM_TAG(SYM, TAG) \
1760 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
1761 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
1764 #define OTF_TAG_STR(TAG, P) \
1766 (P)[0] = (char) (TAG >> 24); \
1767 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
1768 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
1769 (P)[3] = (char) (TAG & 0xFF); \
1773 static struct OpenTypeSpec *
1774 macfont_get_open_type_spec (Lisp_Object otf_spec)
1776 struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1783 spec->script = XCAR (otf_spec);
1784 if (! NILP (spec->script))
1786 OTF_SYM_TAG (spec->script, spec->script_tag);
1787 val = assq_no_quit (spec->script, Votf_script_alist);
1788 if (CONSP (val) && SYMBOLP (XCDR (val)))
1789 spec->script = XCDR (val);
1791 spec->script = Qnil;
1794 spec->script_tag = 0x44464C54; /* "DFLT" */
1795 otf_spec = XCDR (otf_spec);
1796 spec->langsys_tag = 0;
1797 if (! NILP (otf_spec))
1799 val = XCAR (otf_spec);
1801 OTF_SYM_TAG (val, spec->langsys_tag);
1802 otf_spec = XCDR (otf_spec);
1804 spec->nfeatures[0] = spec->nfeatures[1] = 0;
1805 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1809 val = XCAR (otf_spec);
1812 len = Flength (val);
1814 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1816 : malloc (XINT (len) * sizeof *spec->features[i]));
1817 if (! spec->features[i])
1819 if (i > 0 && spec->features[0])
1820 free (spec->features[0]);
1824 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1826 if (NILP (XCAR (val)))
1832 OTF_SYM_TAG (XCAR (val), tag);
1833 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1836 spec->nfeatures[i] = j;
1841 static CFMutableDictionaryRef
1842 macfont_create_attributes_with_spec (Lisp_Object spec)
1844 Lisp_Object tmp, extra;
1845 CFMutableArrayRef langarray = NULL;
1846 CFCharacterSetRef charset = NULL;
1847 CFStringRef charset_string = NULL;
1848 CFMutableDictionaryRef attributes = NULL, traits = NULL;
1849 Lisp_Object script = Qnil;
1850 Lisp_Object registry;
1851 int cf_charset_idx, i;
1852 struct OpenTypeSpec *otspec = NULL;
1854 enum font_property_index index;
1857 } numeric_traits[] =
1858 {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1859 {{-0.4, 50}, /* light */
1860 {-0.24, 87.5}, /* (semi-light + normal) / 2 */
1861 {0, 100}, /* normal */
1862 {0.24, 140}, /* (semi-bold + normal) / 2 */
1863 {0.4, 200}, /* bold */
1864 {CGFLOAT_MAX, CGFLOAT_MAX}}},
1865 {FONT_SLANT_INDEX, kCTFontSlantTrait,
1866 {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1867 {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1868 {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1870 registry = AREF (spec, FONT_REGISTRY_INDEX);
1872 || EQ (registry, Qascii_0)
1873 || EQ (registry, Qiso10646_1)
1874 || EQ (registry, Qunicode_bmp))
1875 cf_charset_idx = -1;
1880 cf_charset_idx = macfont_get_charset (registry);
1881 if (cf_charset_idx < 0)
1883 charset = cf_charset_table[cf_charset_idx].cf_charset;
1884 charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1885 lang = cf_charset_table[cf_charset_idx].lang;
1888 langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1891 CFArrayAppendValue (langarray, lang);
1895 for (extra = AREF (spec, FONT_EXTRA_INDEX);
1896 CONSP (extra); extra = XCDR (extra))
1898 Lisp_Object key, val;
1901 key = XCAR (tmp), val = XCDR (tmp);
1902 if (EQ (key, QClang))
1905 langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1910 for (; CONSP (val); val = XCDR (val))
1911 if (SYMBOLP (XCAR (val)))
1914 cfstring_create_with_string_noencode (SYMBOL_NAME
1919 CFArrayAppendValue (langarray, lang);
1923 else if (EQ (key, QCotf))
1925 otspec = macfont_get_open_type_spec (val);
1928 script = otspec->script;
1930 else if (EQ (key, QCscript))
1934 if (! NILP (script) && ! charset)
1936 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1938 if (CONSP (chars) && CONSP (CDR (chars)))
1940 CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1941 CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1943 if (! string || !cs)
1951 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1952 if (CHARACTERP (XCAR (chars)))
1954 UniChar unichars[2];
1956 macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1958 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1960 CFStringAppendCharacters (string, unichars, count);
1961 CFCharacterSetAddCharactersInRange (cs, range);
1964 /* CFCharacterSetCreateWithCharactersInString does not
1965 handle surrogate pairs properly as of Mac OS X 10.5. */
1966 charset_string = string;
1970 attributes = CFDictionaryCreateMutable (NULL, 0,
1971 &kCFTypeDictionaryKeyCallBacks,
1972 &kCFTypeDictionaryValueCallBacks);
1976 tmp = AREF (spec, FONT_FAMILY_INDEX);
1977 if (SYMBOLP (tmp) && ! NILP (tmp))
1979 CFStringRef family = macfont_create_family_with_symbol (tmp);
1983 CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
1988 traits = CFDictionaryCreateMutable (NULL, 4,
1989 &kCFTypeDictionaryKeyCallBacks,
1990 &kCFTypeDictionaryValueCallBacks);
1994 for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1996 tmp = AREF (spec, numeric_traits[i].index);
1999 CGPoint *point = numeric_traits[i].points;
2000 CGFloat floatval = (XINT (tmp) >> 8); // XXX
2003 while (point->y < floatval)
2005 if (point == numeric_traits[i].points)
2007 else if (point->y == CGFLOAT_MAX)
2009 floatval = (point - 1)->x + ((floatval - (point - 1)->y)
2010 * ((point->x - (point - 1)->x)
2011 / (point->y - (point - 1)->y)));
2014 else if (floatval < -1.0)
2016 num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2019 CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2023 if (CFDictionaryGetCount (traits))
2024 CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2027 CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2030 CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2033 CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2040 CFRelease (attributes);
2045 if (langarray) CFRelease (langarray);
2046 if (charset && cf_charset_idx < 0) CFRelease (charset);
2047 if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2048 if (traits) CFRelease (traits);
2051 if (otspec->nfeatures[0] > 0)
2052 free (otspec->features[0]);
2053 if (otspec->nfeatures[1] > 0)
2054 free (otspec->features[1]);
2062 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2063 CFCharacterSetRef charset,
2065 CFArrayRef languages)
2067 Boolean result = true;
2069 if (charset || VECTORP (chars))
2071 CFCharacterSetRef desc_charset =
2072 CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2074 if (desc_charset == NULL)
2079 result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2080 else /* VECTORP (chars) */
2084 for (j = 0; j < ASIZE (chars); j++)
2085 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2086 && CFCharacterSetIsLongCharacterMember (desc_charset,
2087 XFASTINT (AREF (chars, j))))
2089 if (j == ASIZE (chars))
2092 CFRelease (desc_charset);
2095 if (result && languages)
2096 result = mac_font_descriptor_supports_languages (desc, languages);
2102 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2103 CTFontSymbolicTraits sym_traits2)
2105 CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2108 /* We prefer synthetic bold of italic to synthetic italic of bold
2109 when both bold and italic are available but bold-italic is not
2111 if (diff & kCTFontTraitBold)
2112 distance |= (1 << 0);
2113 if (diff & kCTFontTraitItalic)
2114 distance |= (1 << 1);
2115 if (diff & kCTFontTraitMonoSpace)
2116 distance |= (1 << 2);
2122 macfont_closest_traits_index_p (CFArrayRef traits_array,
2123 CTFontSymbolicTraits target,
2126 CFIndex i, count = CFArrayGetCount (traits_array);
2127 CTFontSymbolicTraits traits;
2130 traits = ((CTFontSymbolicTraits) (uintptr_t)
2131 CFArrayGetValueAtIndex (traits_array, index));
2132 my_distance = macfont_traits_distance (target, traits);
2134 for (i = 0; i < count; i++)
2137 traits = ((CTFontSymbolicTraits) (uintptr_t)
2138 CFArrayGetValueAtIndex (traits_array, i));
2139 if (macfont_traits_distance (target, traits) < my_distance)
2147 macfont_list (struct frame *f, Lisp_Object spec)
2149 Lisp_Object val = Qnil, family, extra;
2151 CFStringRef family_name = NULL;
2152 CFMutableDictionaryRef attributes = NULL, traits;
2153 Lisp_Object chars = Qnil;
2155 CTFontSymbolicTraits synth_sym_traits = 0;
2156 CFArrayRef families;
2157 CFIndex families_count;
2158 CFCharacterSetRef charset = NULL;
2159 CFArrayRef languages = NULL;
2163 family = AREF (spec, FONT_FAMILY_INDEX);
2164 if (! NILP (family))
2166 family_name = macfont_create_family_with_symbol (family);
2167 if (family_name == NULL)
2171 attributes = macfont_create_attributes_with_spec (spec);
2175 languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2177 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2178 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2180 traits = ((CFMutableDictionaryRef)
2181 CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2183 n = FONT_SLANT_NUMERIC (spec);
2184 if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2186 synth_sym_traits |= kCTFontTraitItalic;
2188 CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2191 n = FONT_WEIGHT_NUMERIC (spec);
2192 if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2194 synth_sym_traits |= kCTFontTraitBold;
2196 CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2200 && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2202 CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2204 if (CFStringHasPrefix (language, CFSTR ("ja"))
2205 || CFStringHasPrefix (language, CFSTR ("ko"))
2206 || CFStringHasPrefix (language, CFSTR ("zh")))
2207 synth_sym_traits |= kCTFontTraitMonoSpace;
2210 /* Create array of families. */
2212 families = CFArrayCreate (NULL, (const void **) &family_name,
2213 1, &kCFTypeArrayCallBacks);
2216 CFStringRef pref_family;
2217 CFIndex families_count, pref_family_index = -1;
2219 families = macfont_copy_available_families_cache ();
2220 if (families == NULL)
2223 families_count = CFArrayGetCount (families);
2225 /* Move preferred family to the front if exists. */
2227 mac_font_create_preferred_family_for_attributes (attributes);
2231 CFArrayGetFirstIndexOfValue (families,
2232 CFRangeMake (0, families_count),
2234 CFRelease (pref_family);
2236 if (pref_family_index > 0)
2238 CFMutableArrayRef mutable_families =
2239 CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2241 if (mutable_families)
2243 CFArrayAppendValue (mutable_families,
2244 CFArrayGetValueAtIndex (families,
2245 pref_family_index));
2246 CFArrayAppendArray (mutable_families, families,
2247 CFRangeMake (0, pref_family_index));
2248 if (pref_family_index + 1 < families_count)
2249 CFArrayAppendArray (mutable_families, families,
2250 CFRangeMake (pref_family_index + 1,
2252 - (pref_family_index + 1)));
2253 CFRelease (families);
2254 families = mutable_families;
2259 charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2263 CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2267 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2270 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2271 if (CONSP (val) && VECTORP (XCDR (val)))
2279 CFRetain (languages);
2280 CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2284 extra = AREF (spec, FONT_EXTRA_INDEX);
2285 families_count = CFArrayGetCount (families);
2286 for (i = 0; i < families_count; i++)
2288 CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2289 CTFontDescriptorRef pat_desc;
2291 CFIndex descs_count;
2292 CFMutableArrayRef filtered_descs, traits_array;
2296 CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2298 pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2302 /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2303 10.7 returns NULL if pat_desc represents the LastResort font.
2304 So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2305 trailing "s") for such a font. */
2306 if (!CFEqual (family_name, CFSTR ("LastResort")))
2307 descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2310 CTFontDescriptorRef lr_desc =
2311 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2314 descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2315 &kCFTypeArrayCallBacks);
2316 CFRelease (lr_desc);
2321 CFRelease (pat_desc);
2325 descs_count = CFArrayGetCount (descs);
2326 if (descs_count == 0
2327 || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2336 CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2337 traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2338 for (j = 0; j < descs_count; j++)
2340 CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2341 CFDictionaryRef dict;
2343 CTFontSymbolicTraits sym_traits;
2345 dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2349 num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2352 || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2356 && !(synth_sym_traits & kCTFontTraitMonoSpace)
2357 && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2358 != (spacing >= FONT_SPACING_MONO)))
2361 /* Don't use a color bitmap font until it is supported on
2363 if (sym_traits & kCTFontTraitColorGlyphs)
2367 && !macfont_supports_charset_and_languages_p (desc, charset,
2371 CFArrayAppendValue (filtered_descs, desc);
2372 CFArrayAppendValue (traits_array,
2373 (const void *) (uintptr_t) sym_traits);
2377 descs = filtered_descs;
2378 descs_count = CFArrayGetCount (descs);
2380 for (j = 0; j < descs_count; j++)
2382 CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2383 CTFontSymbolicTraits sym_traits =
2384 ((CTFontSymbolicTraits) (uintptr_t)
2385 CFArrayGetValueAtIndex (traits_array, j));
2386 CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2388 mask_min = ((synth_sym_traits ^ sym_traits)
2389 & (kCTFontTraitItalic | kCTFontTraitBold));
2390 if (FONT_SLANT_NUMERIC (spec) < 0)
2391 mask_min &= ~kCTFontTraitItalic;
2392 if (FONT_WEIGHT_NUMERIC (spec) < 0)
2393 mask_min &= ~kCTFontTraitBold;
2395 mask_max = (synth_sym_traits & ~sym_traits);
2396 /* Synthetic bold does not work for bitmap-only fonts on Mac
2398 if ((mask_min ^ mask_max) & kCTFontTraitBold)
2400 CFNumberRef format =
2401 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2405 uint32_t format_val;
2407 if (CFNumberGetValue (format, kCFNumberSInt32Type,
2409 && format_val == kCTFontFormatBitmap)
2410 mask_max &= ~kCTFontTraitBold;
2414 mask_min |= (mask_max & kCTFontTraitMonoSpace);
2416 for (mmask = (mask_min & kCTFontTraitMonoSpace);
2417 mmask <= (mask_max & kCTFontTraitMonoSpace);
2418 mmask += kCTFontTraitMonoSpace)
2419 for (bmask = (mask_min & kCTFontTraitBold);
2420 bmask <= (mask_max & kCTFontTraitBold);
2421 bmask += kCTFontTraitBold)
2422 for (imask = (mask_min & kCTFontTraitItalic);
2423 imask <= (mask_max & kCTFontTraitItalic);
2424 imask += kCTFontTraitItalic)
2426 CTFontSymbolicTraits synth = (imask | bmask | mmask);
2429 || macfont_closest_traits_index_p (traits_array,
2430 (sym_traits | synth),
2433 entity = macfont_descriptor_entity (desc, extra, synth);
2434 if (! NILP (entity))
2435 val = Fcons (entity, val);
2440 CFRelease (traits_array);
2444 CFRelease (families);
2445 val = Fnreverse (val);
2451 FONT_ADD_LOG ("macfont-list", spec, val);
2452 if (charset) CFRelease (charset);
2453 if (languages) CFRelease (languages);
2454 if (attributes) CFRelease (attributes);
2455 if (family_name) CFRelease (family_name);
2463 macfont_match (struct frame * frame, Lisp_Object spec)
2465 Lisp_Object entity = Qnil;
2466 CFMutableDictionaryRef attributes;
2467 CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2471 attributes = macfont_create_attributes_with_spec (spec);
2474 pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2475 CFRelease (attributes);
2479 desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2480 CFRelease (pat_desc);
2484 entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2490 FONT_ADD_LOG ("macfont-match", spec, entity);
2495 macfont_list_family (struct frame *frame)
2497 Lisp_Object list = Qnil;
2498 CFArrayRef families;
2502 families = macfont_copy_available_families_cache ();
2505 CFIndex i, count = CFArrayGetCount (families);
2507 for (i = 0; i < count; i++)
2508 list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2509 CFRelease (families);
2518 macfont_free_entity (Lisp_Object entity)
2520 Lisp_Object val = assq_no_quit (QCfont_entity,
2521 AREF (entity, FONT_EXTRA_INDEX));
2522 CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2530 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2532 Lisp_Object val, font_object;
2533 CFStringRef font_name;
2534 struct macfont_info *macfont_info = NULL;
2538 CTFontSymbolicTraits sym_traits;
2541 CGFloat ascent, descent, leading;
2543 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2545 || XTYPE (XCDR (val)) != Lisp_Misc
2546 || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2548 font_name = XSAVE_POINTER (XCDR (val), 0);
2549 sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2551 size = XINT (AREF (entity, FONT_SIZE_INDEX));
2556 macfont = CTFontCreateWithName (font_name, size, NULL);
2559 int fontsize = (int) [((NSFont *) macfont) pointSize];
2560 if (fontsize != size) size = fontsize;
2566 font_object = font_build_object (VECSIZE (struct macfont_info),
2567 Qmac_ct, entity, size);
2568 font = XFONT_OBJECT (font_object);
2569 font->pixel_size = size;
2570 font->driver = &macfont_driver;
2571 font->encoding_charset = font->repertory_charset = -1;
2575 macfont_info = (struct macfont_info *) font;
2576 macfont_info->macfont = macfont;
2577 macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2579 val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2580 if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2581 macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2584 macfont_info->screen_font = NULL;
2585 macfont_info->cache = macfont_lookup_cache (font_name);
2586 macfont_retain_cache (macfont_info->cache);
2587 macfont_info->metrics = NULL;
2588 macfont_info->metrics_nrows = 0;
2589 macfont_info->synthetic_italic_p = 0;
2590 macfont_info->synthetic_bold_p = 0;
2591 macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2592 macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2593 if (!(sym_traits & kCTFontTraitItalic)
2594 && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2595 macfont_info->synthetic_italic_p = 1;
2596 if (!(sym_traits & kCTFontTraitBold)
2597 && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2598 macfont_info->synthetic_bold_p = 1;
2599 if (sym_traits & kCTFontTraitMonoSpace)
2600 macfont_info->spacing = MACFONT_SPACING_MONO;
2601 else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2602 && (XINT (AREF (entity, FONT_SPACING_INDEX))
2603 == FONT_SPACING_SYNTHETIC_MONO))
2604 macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2605 if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2606 macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2609 val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2611 macfont_info->antialias =
2612 NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2614 macfont_info->color_bitmap_p = 0;
2615 if (sym_traits & kCTFontTraitColorGlyphs)
2616 macfont_info->color_bitmap_p = 1;
2618 glyph = macfont_get_glyph_for_character (font, ' ');
2619 if (glyph != kCGFontIndexInvalid)
2620 font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2622 /* dirty workaround */
2623 font->space_width = pixel_size;
2625 total_width = font->space_width;
2626 for (i = 1; i < 95; i++)
2628 glyph = macfont_get_glyph_for_character (font, ' ' + i);
2629 if (glyph == kCGFontIndexInvalid)
2631 total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2634 font->average_width = total_width / 95;
2636 font->average_width = font->space_width; /* XXX */
2638 if (!(macfont_info->screen_font
2639 && mac_screen_font_get_metrics (macfont_info->screen_font,
2640 &ascent, &descent, &leading)))
2642 CFStringRef family_name;
2644 ascent = CTFontGetAscent (macfont);
2645 descent = CTFontGetDescent (macfont);
2646 leading = CTFontGetLeading (macfont);
2647 /* AppKit and WebKit do some adjustment to the heights of
2648 Courier, Helvetica, and Times. */
2649 family_name = CTFontCopyFamilyName (macfont);
2652 if (CFEqual (family_name, CFSTR ("Courier"))
2653 || CFEqual (family_name, CFSTR ("Helvetica"))
2654 || CFEqual (family_name, CFSTR ("Times")))
2655 ascent += (ascent + descent) * .15f;
2656 else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2661 CFRelease (family_name);
2664 font->ascent = ascent + 0.5f;
2665 val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2666 if (CONSP (val) && !NILP (XCDR (val)))
2667 font->descent = descent + 0.5f;
2669 font->descent = descent + leading + 0.5f;
2670 font->height = font->ascent + font->descent;
2672 font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2673 font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2677 /* Unfortunately Xft doesn't provide a way to get minimum char
2678 width. So, we use space_width instead. */
2679 font->min_width = font->max_width = font->space_width; /* XXX */
2681 font->baseline_offset = 0;
2682 font->relative_compose = 0;
2683 font->default_ascent = 0;
2684 font->vertical_centering = 0;
2690 macfont_close (struct font *font)
2692 struct macfont_info *macfont_info = (struct macfont_info *) font;
2694 if (macfont_info->cache)
2699 CFRelease (macfont_info->macfont);
2700 CGFontRelease (macfont_info->cgfont);
2701 if (macfont_info->screen_font)
2702 CFRelease (macfont_info->screen_font);
2703 macfont_release_cache (macfont_info->cache);
2704 for (i = 0; i < macfont_info->metrics_nrows; i++)
2705 if (macfont_info->metrics[i])
2706 xfree (macfont_info->metrics[i]);
2707 if (macfont_info->metrics)
2708 xfree (macfont_info->metrics);
2709 macfont_info->cache = NULL;
2715 macfont_has_char (Lisp_Object font, int c)
2718 CFCharacterSetRef charset;
2721 if (FONT_ENTITY_P (font))
2726 val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2728 name = XSAVE_POINTER (val, 0);
2729 charset = macfont_get_cf_charset_for_name (name);
2732 charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2734 result = CFCharacterSetIsLongCharacterMember (charset, c);
2741 macfont_encode_char (struct font *font, int c)
2746 glyph = macfont_get_glyph_for_character (font, c);
2749 return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2753 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2754 struct font_metrics *metrics)
2759 width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2760 for (i = 1; i < nglyphs; i++)
2762 struct font_metrics m;
2763 int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2768 if (width + m.lbearing < metrics->lbearing)
2769 metrics->lbearing = width + m.lbearing;
2770 if (width + m.rbearing > metrics->rbearing)
2771 metrics->rbearing = width + m.rbearing;
2772 if (m.ascent > metrics->ascent)
2773 metrics->ascent = m.ascent;
2774 if (m.descent > metrics->descent)
2775 metrics->descent = m.descent;
2782 metrics->width = width;
2786 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2787 bool with_background)
2789 struct frame * f = s->f;
2790 struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2791 CGRect background_rect;
2792 CGPoint text_position;
2795 CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2796 bool no_antialias_p =
2797 (NILP (ns_antialias_text)
2798 || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2799 || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2800 && font_size <= macfont_antialias_threshold));
2801 int len = to - from;
2802 struct face *face = s->face;
2803 CGContextRef context;
2807 if (with_background)
2808 background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2809 s->width, FONT_HEIGHT (s->font));
2811 background_rect = CGRectNull;
2813 text_position = CGPointMake (x, -y);
2814 glyphs = xmalloc (sizeof (CGGlyph) * len);
2816 CGFloat advance_delta = 0;
2818 CGFloat total_width = 0;
2820 positions = xmalloc (sizeof (CGPoint) * len);
2821 for (i = 0; i < len; i++)
2825 glyphs[i] = s->char2b[from + i];
2826 width = (s->padding_p ? 1
2827 : macfont_glyph_extents (s->font, glyphs[i],
2828 NULL, &advance_delta,
2830 positions[i].x = total_width + advance_delta;
2832 total_width += width;
2836 context = [[NSGraphicsContext currentContext] graphicsPort];
2837 CGContextSaveGState (context);
2839 if (!CGRectIsNull (background_rect))
2841 if (s->hl == DRAW_MOUSE_FACE)
2843 face = FACE_FROM_ID_OR_NULL (s->f,
2844 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2846 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2848 CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2849 CGContextFillRects (context, &background_rect, 1);
2852 if (macfont_info->cgfont)
2854 CGAffineTransform atfm;
2856 CGContextScaleCTM (context, 1, -1);
2857 CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2858 if (macfont_info->synthetic_italic_p)
2859 atfm = synthetic_italic_atfm;
2861 atfm = CGAffineTransformIdentity;
2862 if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2864 CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2866 /* Stroke line width for text drawing is not correctly
2867 scaled on Retina display/HiDPI mode when drawn to screen
2868 (whereas it is correctly scaled when drawn to bitmaps),
2869 and synthetic bold looks thinner on such environments.
2870 Apple says there are no plans to address this issue
2871 (rdar://11644870) currently. So we add a workaround. */
2872 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
2873 CGContextSetLineWidth (context, synthetic_bold_factor * font_size
2874 * [[FRAME_NS_VIEW(f) window] backingScaleFactor]);
2876 CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2878 CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2881 CGContextSetShouldAntialias (context, false);
2883 CGContextSetTextMatrix (context, atfm);
2884 CGContextSetTextPosition (context, text_position.x, text_position.y);
2886 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2887 if (macfont_info->color_bitmap_p
2888 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2889 && CTFontDrawGlyphs != NULL
2895 CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2900 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2902 CGContextSetFont (context, macfont_info->cgfont);
2903 CGContextSetFontSize (context, font_size);
2904 CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2911 CGContextRestoreGState (context);
2919 macfont_shape (Lisp_Object lgstring)
2921 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2922 struct macfont_info *macfont_info = (struct macfont_info *) font;
2923 CTFontRef macfont = macfont_info->macfont;
2924 ptrdiff_t glyph_len, len, i, j;
2927 CFIndex *nonbmp_indices;
2930 struct mac_glyph_layout *glyph_layouts;
2932 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2934 for (i = 0; i < glyph_len; i++)
2936 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2940 if (LGLYPH_CHAR (lglyph) >= 0x10000)
2946 if (INT_MAX / 2 < len)
2947 memory_full (SIZE_MAX);
2949 unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2950 nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2951 for (i = j = 0; i < len; i++)
2953 UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2955 if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2957 nonbmp_indices[j] = i + j;
2961 nonbmp_indices[j] = len + j; /* sentinel */
2965 string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2969 glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2970 if (macfont_info->screen_font)
2971 used = mac_screen_font_shape (macfont_info->screen_font, string,
2972 glyph_layouts, glyph_len);
2974 used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2985 for (i = 0; i < used; i++)
2987 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2988 struct mac_glyph_layout *gl = glyph_layouts + i;
2990 struct font_metrics metrics;
2991 int xoff, yoff, wadjust;
2995 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2996 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2999 from = gl->comp_range.location;
3000 /* Convert UTF-16 index to UTF-32. */
3002 while (nonbmp_indices[j] < from)
3005 LGLYPH_SET_FROM (lglyph, from);
3007 to = gl->comp_range.location + gl->comp_range.length;
3008 /* Convert UTF-16 index to UTF-32. */
3009 while (nonbmp_indices[j] < to)
3012 LGLYPH_SET_TO (lglyph, to - 1);
3014 /* LGLYPH_CHAR is used in `describe-char' for checking whether
3015 the composition is trivial. */
3019 if (unichars[gl->string_index] >= 0xD800
3020 && unichars[gl->string_index] < 0xDC00)
3021 c = (((unichars[gl->string_index] - 0xD800) << 10)
3022 + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3024 c = unichars[gl->string_index];
3025 if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3027 LGLYPH_SET_CHAR (lglyph, c);
3031 unsigned long cc = gl->glyph_id;
3032 LGLYPH_SET_CODE (lglyph, cc);
3035 macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3036 LGLYPH_SET_WIDTH (lglyph, metrics.width);
3037 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3038 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3039 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3040 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3042 xoff = lround (gl->advance_delta);
3043 yoff = lround (- gl->baseline_delta);
3044 wadjust = lround (gl->advance);
3045 if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3049 vec = Fmake_vector (make_number (3), Qnil);
3050 ASET (vec, 0, make_number (xoff));
3051 ASET (vec, 1, make_number (yoff));
3052 ASET (vec, 2, make_number (wadjust));
3053 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3059 return make_number (used);
3062 /* Structures for the UVS subtable (format 14) in the cmap table. */
3063 typedef UInt8 UINT24[3];
3065 #pragma pack(push, 1)
3066 struct variation_selector_record
3068 UINT24 var_selector;
3069 UInt32 default_uvs_offset, non_default_uvs_offset;
3074 UInt32 length, num_var_selector_records;
3075 struct variation_selector_record variation_selector_records[1];
3077 #define SIZEOF_UVS_TABLE_HEADER \
3078 (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3080 struct unicode_value_range
3082 UINT24 start_unicode_value;
3083 UInt8 additional_count;
3085 struct default_uvs_table {
3086 UInt32 num_unicode_value_ranges;
3087 struct unicode_value_range unicode_value_ranges[1];
3089 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3090 (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3094 UINT24 unicode_value;
3097 struct non_default_uvs_table
3099 UInt32 num_uvs_mappings;
3100 struct uvs_mapping uvs_mappings[1];
3102 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3103 (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3106 /* Read big endian values. The argument LVAL must be an lvalue. */
3107 /* I suppose OSReadBigInt* takes care of unaligned data. At least, we
3108 can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3109 OSReadBigInt16(cdb, 7);" in a sample code by Apple. */
3110 #define BUINT8_VALUE(lval) (*((UInt8 *) &(lval)))
3111 #define BUINT16_VALUE(lval) OSReadBigInt16 (&(lval), 0)
3112 /* Succeeding one byte should also be accessible. */
3113 #define BUINT24_VALUE(lval) (OSReadBigInt32 (&(lval), 0) >> 8)
3114 #define BUINT32_VALUE(lval) OSReadBigInt32 (&(lval), 0)
3116 /* Return UVS subtable for the specified FONT. If the subtable is not
3117 found or ill-formatted, then return NULL. */
3120 mac_font_copy_uvs_table (CTFontRef font)
3122 CFDataRef cmap_table, uvs_table = NULL;
3124 cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3125 kCTFontTableOptionNoOptions);
3128 sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3129 struct uvs_table *uvs;
3130 struct variation_selector_record *records;
3131 UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3134 if (CFDataGetLength (cmap_table) > UINT32_MAX)
3138 cmap_len = CFDataGetLength (cmap_table);
3139 if (sizeof_sfntCMapHeader > cmap_len)
3142 ntables = BUINT16_VALUE (cmap->numTables);
3143 if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3144 / sizeof_sfntCMapEncoding))
3147 for (i = 0; i < ntables; i++)
3148 if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3149 == kFontUnicodePlatform)
3150 && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3151 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3153 uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3157 || uvs_offset > cmap_len
3158 || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3161 uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3162 uvs_len = BUINT32_VALUE (uvs->length);
3163 if (uvs_len > cmap_len - uvs_offset
3164 || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3167 if (BUINT16_VALUE (uvs->format) != 14)
3170 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3171 if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3172 / sizeof (struct variation_selector_record)))
3175 records = uvs->variation_selector_records;
3176 for (i = 0; i < nrecords; i++)
3178 UInt32 default_uvs_offset, non_default_uvs_offset;
3180 default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3181 if (default_uvs_offset)
3183 struct default_uvs_table *default_uvs;
3186 if (default_uvs_offset > uvs_len
3187 || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3188 > uvs_len - default_uvs_offset))
3191 default_uvs = ((struct default_uvs_table *)
3192 ((UInt8 *) uvs + default_uvs_offset));
3193 nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3194 if (nranges > ((uvs_len - default_uvs_offset
3195 - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3196 / sizeof (struct unicode_value_range)))
3198 /* Now 2 * nranges can't overflow, so we can safely use
3199 `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3200 mac_font_get_glyphs_for_variants. */
3203 non_default_uvs_offset =
3204 BUINT32_VALUE (records[i].non_default_uvs_offset);
3205 if (non_default_uvs_offset)
3207 struct non_default_uvs_table *non_default_uvs;
3210 if (non_default_uvs_offset > uvs_len
3211 || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3212 > uvs_len - non_default_uvs_offset))
3215 non_default_uvs = ((struct non_default_uvs_table *)
3216 ((UInt8 *) uvs + non_default_uvs_offset));
3217 nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3218 if (nmappings > ((uvs_len - non_default_uvs_offset
3219 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3220 / sizeof (struct uvs_mapping)))
3222 /* Now 2 * nmappings can't overflow, so we can safely
3223 use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3224 in mac_font_get_glyphs_for_variants. */
3228 uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3231 CFRelease (cmap_table);
3237 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3238 sequence consisting of the given base character C and each
3239 variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3240 result (explained below) into the corresponding GLYPHS[i]. If the
3241 entry is found in the Default UVS Table, then the result is 0. If
3242 the entry is found in the Non-Default UVS Table, then the result is
3243 the associated glyph ID. Otherwise, kCGFontIndexInvalid. The
3244 elements in SELECTORS must be sorted in strictly increasing
3248 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3249 const UTF32Char selectors[], CGGlyph glyphs[],
3252 struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3253 struct variation_selector_record *records = uvs->variation_selector_records;
3255 UInt32 ir, nrecords;
3256 dispatch_queue_t queue =
3257 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3258 dispatch_group_t group = dispatch_group_create ();
3260 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3263 while (i < count && ir < nrecords)
3265 UInt32 default_uvs_offset, non_default_uvs_offset;
3267 if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3269 glyphs[i++] = kCGFontIndexInvalid;
3272 else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3278 /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3279 default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3280 non_default_uvs_offset =
3281 BUINT32_VALUE (records[ir].non_default_uvs_offset);
3282 dispatch_group_async (group, queue, ^{
3283 glyphs[i] = kCGFontIndexInvalid;
3285 if (default_uvs_offset)
3287 struct default_uvs_table *default_uvs =
3288 (struct default_uvs_table *) ((UInt8 *) uvs
3289 + default_uvs_offset);
3290 struct unicode_value_range *ranges =
3291 default_uvs->unicode_value_ranges;
3295 hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3298 UInt32 mid = (lo + hi) / 2;
3300 if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3306 && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3307 + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3311 if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3313 struct non_default_uvs_table *non_default_uvs =
3314 (struct non_default_uvs_table *) ((UInt8 *) uvs
3315 + non_default_uvs_offset);
3316 struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3320 hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3323 UInt32 mid = (lo + hi) / 2;
3325 if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3331 BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3332 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3339 glyphs[i++] = kCGFontIndexInvalid;
3340 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3341 dispatch_release (group);
3345 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3347 CFDataRef uvs_table;
3348 NSCharacterCollection uvs_collection;
3352 uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3356 UTF32Char selectors[256];
3357 CGGlyph glyphs[256];
3359 for (i = 0; i < 16; i++)
3360 selectors[i] = 0xFE00 + i;
3361 for (; i < 256; i++)
3362 selectors[i] = 0xE0100 + (i - 16);
3363 mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3364 for (i = 0; i < 256; i++)
3366 CGGlyph glyph = glyphs[i];
3368 if (uvs_collection != NSIdentityMappingCharacterCollection
3369 && glyph != kCGFontIndexInvalid)
3370 glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3371 if (glyph == kCGFontIndexInvalid)
3375 variations[i] = (glyph ? glyph
3376 : macfont_get_glyph_for_character (font, c));
3386 static const char *const macfont_booleans[] = {
3392 static const char *const macfont_non_booleans[] = {
3400 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3402 font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3406 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3407 CFArrayRef languages)
3409 Boolean result = true;
3410 CFArrayRef desc_languages =
3411 CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3413 if (desc_languages == NULL)
3417 CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3418 CFIndex i, languages_count = CFArrayGetCount (languages);
3420 for (i = 0; i < languages_count; i++)
3422 CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3424 if (!CFArrayContainsValue (desc_languages, range, language)
3425 /* PingFang SC contains "zh" and "zh-Hant" as covered
3426 languages, but does not contain "zh-Hans". */
3427 && !(CFEqual (language, CFSTR ("zh-Hans"))
3428 && CFArrayContainsValue (desc_languages, range,
3435 CFRelease (desc_languages);
3442 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3444 CFStringRef result = NULL;
3445 CFStringRef charset_string =
3446 CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3448 if (charset_string && CFStringGetLength (charset_string) > 0)
3450 CFStringRef keys[] = {
3451 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3452 kCTLanguageAttributeName
3454 CFSTR ("NSLanguage")
3457 CFTypeRef values[] = {NULL};
3458 CFIndex num_values = 0;
3459 CFArrayRef languages
3460 = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3462 if (languages && CFArrayGetCount (languages) > 0)
3464 if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3465 values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3468 CFCharacterSetRef charset =
3469 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3471 result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3476 CFAttributedStringRef attr_string = NULL;
3477 CTLineRef ctline = NULL;
3478 CFDictionaryRef attrs
3479 = CFDictionaryCreate (NULL, (const void **) keys,
3480 (const void **) values, num_values,
3481 &kCFTypeDictionaryKeyCallBacks,
3482 &kCFTypeDictionaryValueCallBacks);
3486 attr_string = CFAttributedStringCreate (NULL, charset_string,
3492 ctline = CTLineCreateWithAttributedString (attr_string);
3493 CFRelease (attr_string);
3497 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3498 CFIndex i, nruns = CFArrayGetCount (runs);
3501 for (i = 0; i < nruns; i++)
3503 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3504 CFDictionaryRef attributes = CTRunGetAttributes (run);
3505 CTFontRef font_in_run;
3507 if (attributes == NULL)
3510 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3511 if (font_in_run == NULL)
3515 else if (!mac_font_equal_in_postscript_name (font,
3519 if (nruns > 0 && i == nruns)
3520 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3529 static inline double
3530 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3532 return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3536 static inline CGRect
3537 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3539 return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3544 mac_font_create_available_families (void)
3546 CFMutableArrayRef families = NULL;
3547 CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3551 CFIndex i, count = CFArrayGetCount (orig_families);
3553 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3555 for (i = 0; i < count; i++)
3557 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3559 if (!CFStringHasPrefix (family, CFSTR ("."))
3560 && (CTFontManagerCompareFontFamilyNames (family,
3561 CFSTR ("LastResort"),
3563 != kCFCompareEqualTo))
3564 CFArrayAppendValue (families, family);
3566 CFRelease (orig_families);
3573 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3576 CFStringRef name1, name2;
3582 name1 = CTFontCopyPostScriptName (font1);
3585 name2 = CTFontCopyPostScriptName (font2);
3588 result = CFEqual (name1, name2);
3598 mac_font_create_line_with_string_and_font (CFStringRef string,
3601 CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3602 CFTypeRef values[] = {NULL, NULL};
3603 CFDictionaryRef attributes = NULL;
3604 CFAttributedStringRef attr_string = NULL;
3605 CTLineRef ctline = NULL;
3606 float float_zero = 0.0f;
3608 values[0] = macfont;
3609 values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3612 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3613 (const void **) values,
3615 &kCFTypeDictionaryKeyCallBacks,
3616 &kCFTypeDictionaryValueCallBacks);
3617 CFRelease (values[1]);
3621 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3622 CFRelease (attributes);
3626 ctline = CTLineCreateWithAttributedString (attr_string);
3627 CFRelease (attr_string);
3631 /* Abandon if ctline contains some fonts other than the
3633 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3634 CFIndex i, nruns = CFArrayGetCount (runs);
3636 for (i = 0; i < nruns; i++)
3638 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3639 CFDictionaryRef attributes = CTRunGetAttributes (run);
3640 CTFontRef font_in_run;
3642 if (attributes == NULL)
3645 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3646 if (font_in_run == NULL)
3648 if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3662 mac_font_shape (CTFontRef font, CFStringRef string,
3663 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3665 CFIndex used, result = 0;
3666 CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3671 used = CTLineGetGlyphCount (ctline);
3672 if (used <= glyph_len)
3674 CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3675 CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3676 CGFloat total_advance = 0;
3677 CFIndex total_glyph_count = 0;
3679 for (k = 0; k < ctrun_count; k++)
3681 CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3682 CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3683 struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3684 CFRange string_range, comp_range, range;
3685 CFIndex *permutation;
3687 if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3688 permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3692 #define RIGHT_TO_LEFT_P permutation
3694 /* Now the `comp_range' member of struct mac_glyph_layout is
3695 temporarily used as a work area such that:
3696 glbuf[i].comp_range.location =
3697 min {compRange[i + 1].location, ...,
3698 compRange[glyph_count - 1].location,
3699 maxRange (stringRangeForCTRun)}
3700 glbuf[i].comp_range.length = maxRange (compRange[i])
3701 where compRange[i] is the range of composed characters
3702 containing i-th glyph. */
3703 string_range = CTRunGetStringRange (ctrun);
3704 min_location = string_range.location + string_range.length;
3705 for (i = 0; i < glyph_count; i++)
3707 struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3708 CFIndex glyph_index;
3711 if (!RIGHT_TO_LEFT_P)
3712 glyph_index = glyph_count - i - 1;
3715 CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3718 CFStringGetRangeOfComposedCharactersAtIndex (string,
3720 gl->comp_range.location = min_location;
3721 gl->comp_range.length = rng.location + rng.length;
3722 if (rng.location < min_location)
3723 min_location = rng.location;
3726 /* Fill the `comp_range' member of struct mac_glyph_layout,
3727 and setup a permutation for right-to-left text. */
3728 comp_range = CFRangeMake (string_range.location, 0);
3729 range = CFRangeMake (0, 0);
3732 struct mac_glyph_layout *gl =
3733 glbuf + range.location + range.length;
3735 if (gl->comp_range.length
3736 > comp_range.location + comp_range.length)
3737 comp_range.length = gl->comp_range.length - comp_range.location;
3738 min_location = gl->comp_range.location;
3741 if (min_location >= comp_range.location + comp_range.length)
3743 comp_range.length = min_location - comp_range.location;
3744 for (i = 0; i < range.length; i++)
3746 glbuf[range.location + i].comp_range = comp_range;
3747 if (RIGHT_TO_LEFT_P)
3748 permutation[range.location + i] =
3749 range.location + range.length - i - 1;
3752 comp_range = CFRangeMake (min_location, 0);
3753 range.location += range.length;
3755 if (range.location == glyph_count)
3760 /* Then fill the remaining members. */
3761 for (range = CFRangeMake (0, 1); range.location < glyph_count;
3764 struct mac_glyph_layout *gl;
3768 if (!RIGHT_TO_LEFT_P)
3769 gl = glbuf + range.location;
3774 src = glyph_count - 1 - range.location;
3775 dest = permutation[src];
3779 CFIndex tmp = gl->string_index;
3781 gl->string_index = glbuf[src].string_index;
3782 glbuf[src].string_index = tmp;
3785 CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3787 CTRunGetPositions (ctrun, range, &position);
3788 max_x = position.x + CTRunGetTypographicBounds (ctrun, range,
3790 max_x = max (max_x, total_advance);
3791 gl->advance_delta = position.x - total_advance;
3792 gl->baseline_delta = position.y;
3793 gl->advance = max_x - total_advance;
3794 total_advance = max_x;
3797 if (RIGHT_TO_LEFT_P)
3798 xfree (permutation);
3800 #undef RIGHT_TO_LEFT_P
3802 total_glyph_count += glyph_count;
3812 /* The function below seems to cause a memory leak for the CFString
3813 created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3814 10.6.3. For now, we use the NSGlyphInfo version instead. */
3815 #if USE_CT_GLYPH_INFO
3817 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3820 CGGlyph result = kCGFontIndexInvalid;
3821 UniChar characters[] = {0xfffd};
3823 CFAttributedStringRef attr_string = NULL;
3824 CTLineRef ctline = NULL;
3826 string = CFStringCreateWithCharacters (NULL, characters,
3827 ARRAYELTS (characters));
3831 CTGlyphInfoRef glyph_info =
3832 CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3833 CFDictionaryRef attributes = NULL;
3837 CFStringRef keys[] = {kCTFontAttributeName,
3838 kCTGlyphInfoAttributeName};
3839 CFTypeRef values[] = {font, glyph_info};
3841 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3842 (const void **) values,
3844 &kCFTypeDictionaryKeyCallBacks,
3845 &kCFTypeDictionaryValueCallBacks);
3846 CFRelease (glyph_info);
3850 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3851 CFRelease (attributes);
3857 ctline = CTLineCreateWithAttributedString (attr_string);
3858 CFRelease (attr_string);
3862 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3864 if (CFArrayGetCount (runs) > 0)
3866 CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3867 CFDictionaryRef attributes = CTRunGetAttributes (run);
3871 CTFontRef font_in_run =
3872 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3875 && mac_font_equal_in_postscript_name (font_in_run, font))
3877 CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3878 if (result >= CTFontGetGlyphCount (font))
3879 result = kCGFontIndexInvalid;
3891 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3893 CFArrayRef result = NULL;
3895 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3896 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3897 if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3900 CTFontRef user_font =
3901 CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3905 CFArrayRef languages =
3906 CFArrayCreate (NULL, (const void **) &language, 1,
3907 &kCFTypeArrayCallBacks);
3911 result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3913 CFRelease (languages);
3915 CFRelease (user_font);
3918 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3919 else /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3921 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3922 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3926 for (i = 0; macfont_language_default_font_names[i].language; i++)
3928 if (CFEqual (macfont_language_default_font_names[i].language,
3931 CFMutableArrayRef descriptors =
3932 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3939 macfont_language_default_font_names[i].font_names[j];
3942 CFDictionaryRef attributes =
3943 CFDictionaryCreate (NULL,
3945 &kCTFontNameAttribute),
3947 &macfont_language_default_font_names[i].font_names[j]),
3948 1, &kCFTypeDictionaryKeyCallBacks,
3949 &kCFTypeDictionaryValueCallBacks);
3953 CTFontDescriptorRef pat_desc =
3954 CTFontDescriptorCreateWithAttributes (attributes);
3958 CTFontDescriptorRef descriptor =
3959 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3963 CFArrayAppendValue (descriptors, descriptor);
3964 CFRelease (descriptor);
3966 CFRelease (pat_desc);
3968 CFRelease (attributes);
3971 result = descriptors;
3983 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3984 CFArrayRef languages)
3986 CFStringRef result = NULL;
3987 CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3988 CFArrayRef descriptors =
3989 mac_font_copy_default_descriptors_for_language (language);
3993 CFIndex i, count = CFArrayGetCount (descriptors);
3995 for (i = 0; i < count; i++)
3997 CTFontDescriptorRef descriptor =
3998 CFArrayGetValueAtIndex (descriptors, i);
4000 if (macfont_supports_charset_and_languages_p (descriptor, charset,
4003 CFStringRef family =
4004 CTFontDescriptorCopyAttribute (descriptor,
4005 kCTFontFamilyNameAttribute);
4008 if (!CFStringHasPrefix (family, CFSTR ("."))
4009 && !CFEqual (family, CFSTR ("LastResort")))
4019 CFRelease (descriptors);
4026 macfont_get_nsctfont (struct font *font)
4028 struct macfont_info *macfont_info = (struct macfont_info *) font;
4029 CTFontRef macfont = macfont_info->macfont;
4031 return (void *) macfont;
4035 mac_register_font_driver (struct frame *f)
4037 register_font_driver (&macfont_driver, f);
4042 syms_of_macfont (void)
4044 /* Core Text, for macOS. */
4045 DEFSYM (Qmac_ct, "mac-ct");
4046 register_font_driver (&macfont_driver, NULL);
4048 /* The font property key specifying the font design destination. The
4049 value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4050 text. (See the documentation of X Logical Font Description
4051 Conventions.) In the Mac font driver, 1 means the screen font is
4052 used for calculating some glyph metrics. You can see the
4053 difference with Monaco 8pt or 9pt, for example. */
4054 DEFSYM (QCdestination, ":destination");
4056 /* The boolean-valued font property key specifying the use of leading. */
4057 DEFSYM (QCminspace, ":minspace");
4059 macfont_family_cache = Qnil;
4060 staticpro (&macfont_family_cache);