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