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 >= 1070
2873 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2874 if ([[FRAME_NS_VIEW(f) window] respondsToSelector:
2875 @selector(backingScaleFactor)])
2877 CGContextSetLineWidth (context, synthetic_bold_factor * font_size
2878 * [[FRAME_NS_VIEW(f) window] backingScaleFactor]);
2879 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2883 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2884 CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2886 CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2889 CGContextSetShouldAntialias (context, false);
2891 CGContextSetTextMatrix (context, atfm);
2892 CGContextSetTextPosition (context, text_position.x, text_position.y);
2894 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2895 if (macfont_info->color_bitmap_p
2896 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2897 && CTFontDrawGlyphs != NULL
2903 CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2908 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2910 CGContextSetFont (context, macfont_info->cgfont);
2911 CGContextSetFontSize (context, font_size);
2912 CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2919 CGContextRestoreGState (context);
2927 macfont_shape (Lisp_Object lgstring)
2929 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2930 struct macfont_info *macfont_info = (struct macfont_info *) font;
2931 CTFontRef macfont = macfont_info->macfont;
2932 ptrdiff_t glyph_len, len, i, j;
2935 CFIndex *nonbmp_indices;
2938 struct mac_glyph_layout *glyph_layouts;
2940 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2942 for (i = 0; i < glyph_len; i++)
2944 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2948 if (LGLYPH_CHAR (lglyph) >= 0x10000)
2954 if (INT_MAX / 2 < len)
2955 memory_full (SIZE_MAX);
2957 unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2958 nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2959 for (i = j = 0; i < len; i++)
2961 UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2963 if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2965 nonbmp_indices[j] = i + j;
2969 nonbmp_indices[j] = len + j; /* sentinel */
2973 string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2977 glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2978 if (macfont_info->screen_font)
2979 used = mac_screen_font_shape (macfont_info->screen_font, string,
2980 glyph_layouts, glyph_len);
2982 used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2993 for (i = 0; i < used; i++)
2995 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2996 struct mac_glyph_layout *gl = glyph_layouts + i;
2998 struct font_metrics metrics;
2999 int xoff, yoff, wadjust;
3003 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
3004 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
3007 from = gl->comp_range.location;
3008 /* Convert UTF-16 index to UTF-32. */
3010 while (nonbmp_indices[j] < from)
3013 LGLYPH_SET_FROM (lglyph, from);
3015 to = gl->comp_range.location + gl->comp_range.length;
3016 /* Convert UTF-16 index to UTF-32. */
3017 while (nonbmp_indices[j] < to)
3020 LGLYPH_SET_TO (lglyph, to - 1);
3022 /* LGLYPH_CHAR is used in `describe-char' for checking whether
3023 the composition is trivial. */
3027 if (unichars[gl->string_index] >= 0xD800
3028 && unichars[gl->string_index] < 0xDC00)
3029 c = (((unichars[gl->string_index] - 0xD800) << 10)
3030 + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3032 c = unichars[gl->string_index];
3033 if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3035 LGLYPH_SET_CHAR (lglyph, c);
3039 unsigned long cc = gl->glyph_id;
3040 LGLYPH_SET_CODE (lglyph, cc);
3043 macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3044 LGLYPH_SET_WIDTH (lglyph, metrics.width);
3045 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3046 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3047 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3048 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3050 xoff = lround (gl->advance_delta);
3051 yoff = lround (- gl->baseline_delta);
3052 wadjust = lround (gl->advance);
3053 if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3057 vec = Fmake_vector (make_number (3), Qnil);
3058 ASET (vec, 0, make_number (xoff));
3059 ASET (vec, 1, make_number (yoff));
3060 ASET (vec, 2, make_number (wadjust));
3061 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3067 return make_number (used);
3070 /* Structures for the UVS subtable (format 14) in the cmap table. */
3071 typedef UInt8 UINT24[3];
3073 #pragma pack(push, 1)
3074 struct variation_selector_record
3076 UINT24 var_selector;
3077 UInt32 default_uvs_offset, non_default_uvs_offset;
3082 UInt32 length, num_var_selector_records;
3083 struct variation_selector_record variation_selector_records[1];
3085 #define SIZEOF_UVS_TABLE_HEADER \
3086 (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3088 struct unicode_value_range
3090 UINT24 start_unicode_value;
3091 UInt8 additional_count;
3093 struct default_uvs_table {
3094 UInt32 num_unicode_value_ranges;
3095 struct unicode_value_range unicode_value_ranges[1];
3097 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3098 (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3102 UINT24 unicode_value;
3105 struct non_default_uvs_table
3107 UInt32 num_uvs_mappings;
3108 struct uvs_mapping uvs_mappings[1];
3110 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3111 (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3114 /* Read big endian values. The argument LVAL must be an lvalue. */
3115 /* I suppose OSReadBigInt* takes care of unaligned data. At least, we
3116 can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3117 OSReadBigInt16(cdb, 7);" in a sample code by Apple. */
3118 #define BUINT8_VALUE(lval) (*((UInt8 *) &(lval)))
3119 #define BUINT16_VALUE(lval) OSReadBigInt16 (&(lval), 0)
3120 /* Succeeding one byte should also be accessible. */
3121 #define BUINT24_VALUE(lval) (OSReadBigInt32 (&(lval), 0) >> 8)
3122 #define BUINT32_VALUE(lval) OSReadBigInt32 (&(lval), 0)
3124 /* Return UVS subtable for the specified FONT. If the subtable is not
3125 found or ill-formatted, then return NULL. */
3128 mac_font_copy_uvs_table (CTFontRef font)
3130 CFDataRef cmap_table, uvs_table = NULL;
3132 cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3133 kCTFontTableOptionNoOptions);
3136 sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3137 struct uvs_table *uvs;
3138 struct variation_selector_record *records;
3139 UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3142 if (CFDataGetLength (cmap_table) > UINT32_MAX)
3146 cmap_len = CFDataGetLength (cmap_table);
3147 if (sizeof_sfntCMapHeader > cmap_len)
3150 ntables = BUINT16_VALUE (cmap->numTables);
3151 if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3152 / sizeof_sfntCMapEncoding))
3155 for (i = 0; i < ntables; i++)
3156 if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3157 == kFontUnicodePlatform)
3158 && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3159 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3161 uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3165 || uvs_offset > cmap_len
3166 || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3169 uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3170 uvs_len = BUINT32_VALUE (uvs->length);
3171 if (uvs_len > cmap_len - uvs_offset
3172 || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3175 if (BUINT16_VALUE (uvs->format) != 14)
3178 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3179 if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3180 / sizeof (struct variation_selector_record)))
3183 records = uvs->variation_selector_records;
3184 for (i = 0; i < nrecords; i++)
3186 UInt32 default_uvs_offset, non_default_uvs_offset;
3188 default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3189 if (default_uvs_offset)
3191 struct default_uvs_table *default_uvs;
3194 if (default_uvs_offset > uvs_len
3195 || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3196 > uvs_len - default_uvs_offset))
3199 default_uvs = ((struct default_uvs_table *)
3200 ((UInt8 *) uvs + default_uvs_offset));
3201 nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3202 if (nranges > ((uvs_len - default_uvs_offset
3203 - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3204 / sizeof (struct unicode_value_range)))
3206 /* Now 2 * nranges can't overflow, so we can safely use
3207 `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3208 mac_font_get_glyphs_for_variants. */
3211 non_default_uvs_offset =
3212 BUINT32_VALUE (records[i].non_default_uvs_offset);
3213 if (non_default_uvs_offset)
3215 struct non_default_uvs_table *non_default_uvs;
3218 if (non_default_uvs_offset > uvs_len
3219 || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3220 > uvs_len - non_default_uvs_offset))
3223 non_default_uvs = ((struct non_default_uvs_table *)
3224 ((UInt8 *) uvs + non_default_uvs_offset));
3225 nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3226 if (nmappings > ((uvs_len - non_default_uvs_offset
3227 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3228 / sizeof (struct uvs_mapping)))
3230 /* Now 2 * nmappings can't overflow, so we can safely
3231 use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3232 in mac_font_get_glyphs_for_variants. */
3236 uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3239 CFRelease (cmap_table);
3245 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3246 sequence consisting of the given base character C and each
3247 variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3248 result (explained below) into the corresponding GLYPHS[i]. If the
3249 entry is found in the Default UVS Table, then the result is 0. If
3250 the entry is found in the Non-Default UVS Table, then the result is
3251 the associated glyph ID. Otherwise, kCGFontIndexInvalid. The
3252 elements in SELECTORS must be sorted in strictly increasing
3256 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3257 const UTF32Char selectors[], CGGlyph glyphs[],
3260 struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3261 struct variation_selector_record *records = uvs->variation_selector_records;
3263 UInt32 ir, nrecords;
3264 dispatch_queue_t queue =
3265 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3266 dispatch_group_t group = dispatch_group_create ();
3268 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3271 while (i < count && ir < nrecords)
3273 UInt32 default_uvs_offset, non_default_uvs_offset;
3275 if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3277 glyphs[i++] = kCGFontIndexInvalid;
3280 else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3286 /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3287 default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3288 non_default_uvs_offset =
3289 BUINT32_VALUE (records[ir].non_default_uvs_offset);
3290 dispatch_group_async (group, queue, ^{
3291 glyphs[i] = kCGFontIndexInvalid;
3293 if (default_uvs_offset)
3295 struct default_uvs_table *default_uvs =
3296 (struct default_uvs_table *) ((UInt8 *) uvs
3297 + default_uvs_offset);
3298 struct unicode_value_range *ranges =
3299 default_uvs->unicode_value_ranges;
3303 hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3306 UInt32 mid = (lo + hi) / 2;
3308 if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3314 && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3315 + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3319 if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3321 struct non_default_uvs_table *non_default_uvs =
3322 (struct non_default_uvs_table *) ((UInt8 *) uvs
3323 + non_default_uvs_offset);
3324 struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3328 hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3331 UInt32 mid = (lo + hi) / 2;
3333 if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3339 BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3340 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3347 glyphs[i++] = kCGFontIndexInvalid;
3348 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3349 dispatch_release (group);
3353 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3355 CFDataRef uvs_table;
3356 NSCharacterCollection uvs_collection;
3360 uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3364 UTF32Char selectors[256];
3365 CGGlyph glyphs[256];
3367 for (i = 0; i < 16; i++)
3368 selectors[i] = 0xFE00 + i;
3369 for (; i < 256; i++)
3370 selectors[i] = 0xE0100 + (i - 16);
3371 mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3372 for (i = 0; i < 256; i++)
3374 CGGlyph glyph = glyphs[i];
3376 if (uvs_collection != NSIdentityMappingCharacterCollection
3377 && glyph != kCGFontIndexInvalid)
3378 glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3379 if (glyph == kCGFontIndexInvalid)
3383 variations[i] = (glyph ? glyph
3384 : macfont_get_glyph_for_character (font, c));
3394 static const char *const macfont_booleans[] = {
3400 static const char *const macfont_non_booleans[] = {
3408 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3410 font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3414 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3415 CFArrayRef languages)
3417 Boolean result = true;
3418 CFArrayRef desc_languages =
3419 CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3421 if (desc_languages == NULL)
3425 CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3426 CFIndex i, languages_count = CFArrayGetCount (languages);
3428 for (i = 0; i < languages_count; i++)
3430 CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3432 if (!CFArrayContainsValue (desc_languages, range, language)
3433 /* PingFang SC contains "zh" and "zh-Hant" as covered
3434 languages, but does not contain "zh-Hans". */
3435 && !(CFEqual (language, CFSTR ("zh-Hans"))
3436 && CFArrayContainsValue (desc_languages, range,
3443 CFRelease (desc_languages);
3450 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3452 CFStringRef result = NULL;
3453 CFStringRef charset_string =
3454 CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3456 if (charset_string && CFStringGetLength (charset_string) > 0)
3458 CFStringRef keys[] = {
3459 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3460 kCTLanguageAttributeName
3462 CFSTR ("NSLanguage")
3465 CFTypeRef values[] = {NULL};
3466 CFIndex num_values = 0;
3467 CFArrayRef languages
3468 = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3470 if (languages && CFArrayGetCount (languages) > 0)
3472 if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3473 values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3476 CFCharacterSetRef charset =
3477 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3479 result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3484 CFAttributedStringRef attr_string = NULL;
3485 CTLineRef ctline = NULL;
3486 CFDictionaryRef attrs
3487 = CFDictionaryCreate (NULL, (const void **) keys,
3488 (const void **) values, num_values,
3489 &kCFTypeDictionaryKeyCallBacks,
3490 &kCFTypeDictionaryValueCallBacks);
3494 attr_string = CFAttributedStringCreate (NULL, charset_string,
3500 ctline = CTLineCreateWithAttributedString (attr_string);
3501 CFRelease (attr_string);
3505 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3506 CFIndex i, nruns = CFArrayGetCount (runs);
3509 for (i = 0; i < nruns; i++)
3511 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3512 CFDictionaryRef attributes = CTRunGetAttributes (run);
3513 CTFontRef font_in_run;
3515 if (attributes == NULL)
3518 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3519 if (font_in_run == NULL)
3523 else if (!mac_font_equal_in_postscript_name (font,
3527 if (nruns > 0 && i == nruns)
3528 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3537 static inline double
3538 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3540 return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3544 static inline CGRect
3545 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3547 return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3552 mac_font_create_available_families (void)
3554 CFMutableArrayRef families = NULL;
3555 CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3559 CFIndex i, count = CFArrayGetCount (orig_families);
3561 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3563 for (i = 0; i < count; i++)
3565 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3567 if (!CFStringHasPrefix (family, CFSTR ("."))
3568 && (CTFontManagerCompareFontFamilyNames (family,
3569 CFSTR ("LastResort"),
3571 != kCFCompareEqualTo))
3572 CFArrayAppendValue (families, family);
3574 CFRelease (orig_families);
3581 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3584 CFStringRef name1, name2;
3590 name1 = CTFontCopyPostScriptName (font1);
3593 name2 = CTFontCopyPostScriptName (font2);
3596 result = CFEqual (name1, name2);
3606 mac_font_create_line_with_string_and_font (CFStringRef string,
3609 CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3610 CFTypeRef values[] = {NULL, NULL};
3611 CFDictionaryRef attributes = NULL;
3612 CFAttributedStringRef attr_string = NULL;
3613 CTLineRef ctline = NULL;
3614 float float_zero = 0.0f;
3616 values[0] = macfont;
3617 values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3620 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3621 (const void **) values,
3623 &kCFTypeDictionaryKeyCallBacks,
3624 &kCFTypeDictionaryValueCallBacks);
3625 CFRelease (values[1]);
3629 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3630 CFRelease (attributes);
3634 ctline = CTLineCreateWithAttributedString (attr_string);
3635 CFRelease (attr_string);
3639 /* Abandon if ctline contains some fonts other than the
3641 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3642 CFIndex i, nruns = CFArrayGetCount (runs);
3644 for (i = 0; i < nruns; i++)
3646 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3647 CFDictionaryRef attributes = CTRunGetAttributes (run);
3648 CTFontRef font_in_run;
3650 if (attributes == NULL)
3653 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3654 if (font_in_run == NULL)
3656 if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3670 mac_font_shape (CTFontRef font, CFStringRef string,
3671 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3673 CFIndex used, result = 0;
3674 CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3679 used = CTLineGetGlyphCount (ctline);
3680 if (used <= glyph_len)
3682 CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3683 CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3684 CGFloat total_advance = 0;
3685 CFIndex total_glyph_count = 0;
3687 for (k = 0; k < ctrun_count; k++)
3689 CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3690 CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3691 struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3692 CFRange string_range, comp_range, range;
3693 CFIndex *permutation;
3695 if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3696 permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3700 #define RIGHT_TO_LEFT_P permutation
3702 /* Now the `comp_range' member of struct mac_glyph_layout is
3703 temporarily used as a work area such that:
3704 glbuf[i].comp_range.location =
3705 min {compRange[i + 1].location, ...,
3706 compRange[glyph_count - 1].location,
3707 maxRange (stringRangeForCTRun)}
3708 glbuf[i].comp_range.length = maxRange (compRange[i])
3709 where compRange[i] is the range of composed characters
3710 containing i-th glyph. */
3711 string_range = CTRunGetStringRange (ctrun);
3712 min_location = string_range.location + string_range.length;
3713 for (i = 0; i < glyph_count; i++)
3715 struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3716 CFIndex glyph_index;
3719 if (!RIGHT_TO_LEFT_P)
3720 glyph_index = glyph_count - i - 1;
3723 CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3726 CFStringGetRangeOfComposedCharactersAtIndex (string,
3728 gl->comp_range.location = min_location;
3729 gl->comp_range.length = rng.location + rng.length;
3730 if (rng.location < min_location)
3731 min_location = rng.location;
3734 /* Fill the `comp_range' member of struct mac_glyph_layout,
3735 and setup a permutation for right-to-left text. */
3736 comp_range = CFRangeMake (string_range.location, 0);
3737 range = CFRangeMake (0, 0);
3740 struct mac_glyph_layout *gl =
3741 glbuf + range.location + range.length;
3743 if (gl->comp_range.length
3744 > comp_range.location + comp_range.length)
3745 comp_range.length = gl->comp_range.length - comp_range.location;
3746 min_location = gl->comp_range.location;
3749 if (min_location >= comp_range.location + comp_range.length)
3751 comp_range.length = min_location - comp_range.location;
3752 for (i = 0; i < range.length; i++)
3754 glbuf[range.location + i].comp_range = comp_range;
3755 if (RIGHT_TO_LEFT_P)
3756 permutation[range.location + i] =
3757 range.location + range.length - i - 1;
3760 comp_range = CFRangeMake (min_location, 0);
3761 range.location += range.length;
3763 if (range.location == glyph_count)
3768 /* Then fill the remaining members. */
3769 for (range = CFRangeMake (0, 1); range.location < glyph_count;
3772 struct mac_glyph_layout *gl;
3776 if (!RIGHT_TO_LEFT_P)
3777 gl = glbuf + range.location;
3782 src = glyph_count - 1 - range.location;
3783 dest = permutation[src];
3787 CFIndex tmp = gl->string_index;
3789 gl->string_index = glbuf[src].string_index;
3790 glbuf[src].string_index = tmp;
3793 CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3795 CTRunGetPositions (ctrun, range, &position);
3796 max_x = position.x + CTRunGetTypographicBounds (ctrun, range,
3798 max_x = max (max_x, total_advance);
3799 gl->advance_delta = position.x - total_advance;
3800 gl->baseline_delta = position.y;
3801 gl->advance = max_x - total_advance;
3802 total_advance = max_x;
3805 if (RIGHT_TO_LEFT_P)
3806 xfree (permutation);
3808 #undef RIGHT_TO_LEFT_P
3810 total_glyph_count += glyph_count;
3820 /* The function below seems to cause a memory leak for the CFString
3821 created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3822 10.6.3. For now, we use the NSGlyphInfo version instead. */
3823 #if USE_CT_GLYPH_INFO
3825 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3828 CGGlyph result = kCGFontIndexInvalid;
3829 UniChar characters[] = {0xfffd};
3831 CFAttributedStringRef attr_string = NULL;
3832 CTLineRef ctline = NULL;
3834 string = CFStringCreateWithCharacters (NULL, characters,
3835 ARRAYELTS (characters));
3839 CTGlyphInfoRef glyph_info =
3840 CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3841 CFDictionaryRef attributes = NULL;
3845 CFStringRef keys[] = {kCTFontAttributeName,
3846 kCTGlyphInfoAttributeName};
3847 CFTypeRef values[] = {font, glyph_info};
3849 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3850 (const void **) values,
3852 &kCFTypeDictionaryKeyCallBacks,
3853 &kCFTypeDictionaryValueCallBacks);
3854 CFRelease (glyph_info);
3858 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3859 CFRelease (attributes);
3865 ctline = CTLineCreateWithAttributedString (attr_string);
3866 CFRelease (attr_string);
3870 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3872 if (CFArrayGetCount (runs) > 0)
3874 CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3875 CFDictionaryRef attributes = CTRunGetAttributes (run);
3879 CTFontRef font_in_run =
3880 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3883 && mac_font_equal_in_postscript_name (font_in_run, font))
3885 CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3886 if (result >= CTFontGetGlyphCount (font))
3887 result = kCGFontIndexInvalid;
3899 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3901 CFArrayRef result = NULL;
3903 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3904 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3905 if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3908 CTFontRef user_font =
3909 CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3913 CFArrayRef languages =
3914 CFArrayCreate (NULL, (const void **) &language, 1,
3915 &kCFTypeArrayCallBacks);
3919 result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3921 CFRelease (languages);
3923 CFRelease (user_font);
3926 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3927 else /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3929 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3930 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3934 for (i = 0; macfont_language_default_font_names[i].language; i++)
3936 if (CFEqual (macfont_language_default_font_names[i].language,
3939 CFMutableArrayRef descriptors =
3940 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3947 macfont_language_default_font_names[i].font_names[j];
3950 CFDictionaryRef attributes =
3951 CFDictionaryCreate (NULL,
3953 &kCTFontNameAttribute),
3955 &macfont_language_default_font_names[i].font_names[j]),
3956 1, &kCFTypeDictionaryKeyCallBacks,
3957 &kCFTypeDictionaryValueCallBacks);
3961 CTFontDescriptorRef pat_desc =
3962 CTFontDescriptorCreateWithAttributes (attributes);
3966 CTFontDescriptorRef descriptor =
3967 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3971 CFArrayAppendValue (descriptors, descriptor);
3972 CFRelease (descriptor);
3974 CFRelease (pat_desc);
3976 CFRelease (attributes);
3979 result = descriptors;
3991 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3992 CFArrayRef languages)
3994 CFStringRef result = NULL;
3995 CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3996 CFArrayRef descriptors =
3997 mac_font_copy_default_descriptors_for_language (language);
4001 CFIndex i, count = CFArrayGetCount (descriptors);
4003 for (i = 0; i < count; i++)
4005 CTFontDescriptorRef descriptor =
4006 CFArrayGetValueAtIndex (descriptors, i);
4008 if (macfont_supports_charset_and_languages_p (descriptor, charset,
4011 CFStringRef family =
4012 CTFontDescriptorCopyAttribute (descriptor,
4013 kCTFontFamilyNameAttribute);
4016 if (!CFStringHasPrefix (family, CFSTR ("."))
4017 && !CFEqual (family, CFSTR ("LastResort")))
4027 CFRelease (descriptors);
4034 macfont_get_nsctfont (struct font *font)
4036 struct macfont_info *macfont_info = (struct macfont_info *) font;
4037 CTFontRef macfont = macfont_info->macfont;
4039 return (void *) macfont;
4043 mac_register_font_driver (struct frame *f)
4045 register_font_driver (&macfont_driver, f);
4050 syms_of_macfont (void)
4052 /* Core Text, for macOS. */
4053 DEFSYM (Qmac_ct, "mac-ct");
4054 register_font_driver (&macfont_driver, NULL);
4056 /* The font property key specifying the font design destination. The
4057 value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4058 text. (See the documentation of X Logical Font Description
4059 Conventions.) In the Mac font driver, 1 means the screen font is
4060 used for calculating some glyph metrics. You can see the
4061 difference with Monaco 8pt or 9pt, for example. */
4062 DEFSYM (QCdestination, ":destination");
4064 /* The boolean-valued font property key specifying the use of leading. */
4065 DEFSYM (QCminspace, ":minspace");
4067 macfont_family_cache = Qnil;
4068 staticpro (&macfont_family_cache);