]> code.delx.au - gnu-emacs/blob - src/macfont.m
* src/macfont.m (macfont_encode_char, syms_of_macfont): Remove unused vars.
[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 CGGlyph glyph;
2769
2770 block_input ();
2771 glyph = macfont_get_glyph_for_character (font, c);
2772 unblock_input ();
2773
2774 return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2775 }
2776
2777 static void
2778 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2779 struct font_metrics *metrics)
2780 {
2781 int width, i;
2782
2783 block_input ();
2784 width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2785 for (i = 1; i < nglyphs; i++)
2786 {
2787 struct font_metrics m;
2788 int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2789 NULL, 0);
2790
2791 if (metrics)
2792 {
2793 if (width + m.lbearing < metrics->lbearing)
2794 metrics->lbearing = width + m.lbearing;
2795 if (width + m.rbearing > metrics->rbearing)
2796 metrics->rbearing = width + m.rbearing;
2797 if (m.ascent > metrics->ascent)
2798 metrics->ascent = m.ascent;
2799 if (m.descent > metrics->descent)
2800 metrics->descent = m.descent;
2801 }
2802 width += w;
2803 }
2804 unblock_input ();
2805
2806 if (metrics)
2807 metrics->width = width;
2808 }
2809
2810 static int
2811 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2812 bool with_background)
2813 {
2814 struct frame * f = s->f;
2815 struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2816 CGRect background_rect;
2817 CGPoint text_position;
2818 CGGlyph *glyphs;
2819 CGPoint *positions;
2820 CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2821 bool no_antialias_p =
2822 (NILP (ns_antialias_text)
2823 || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2824 || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2825 && font_size <= macfont_antialias_threshold));
2826 int len = to - from;
2827 struct face *face = s->face;
2828 CGContextRef context;
2829
2830 block_input ();
2831
2832 if (with_background)
2833 background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2834 s->width, FONT_HEIGHT (s->font));
2835 else
2836 background_rect = CGRectNull;
2837
2838 text_position = CGPointMake (x, -y);
2839 glyphs = xmalloc (sizeof (CGGlyph) * len);
2840 {
2841 CGFloat advance_delta = 0;
2842 int i;
2843 CGFloat total_width = 0;
2844
2845 positions = xmalloc (sizeof (CGPoint) * len);
2846 for (i = 0; i < len; i++)
2847 {
2848 int width;
2849
2850 glyphs[i] = s->char2b[from + i];
2851 width = (s->padding_p ? 1
2852 : macfont_glyph_extents (s->font, glyphs[i],
2853 NULL, &advance_delta,
2854 no_antialias_p));
2855 positions[i].x = total_width + advance_delta;
2856 positions[i].y = 0;
2857 total_width += width;
2858 }
2859 }
2860
2861 context = [[NSGraphicsContext currentContext] graphicsPort];
2862 CGContextSaveGState (context);
2863
2864 if (!CGRectIsNull (background_rect))
2865 {
2866 if (s->hl == DRAW_MOUSE_FACE)
2867 {
2868 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2869 if (!face)
2870 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2871 }
2872 CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2873 CGContextFillRects (context, &background_rect, 1);
2874 }
2875
2876 if (macfont_info->cgfont)
2877 {
2878 CGAffineTransform atfm;
2879
2880 CGContextScaleCTM (context, 1, -1);
2881 CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2882 if (macfont_info->synthetic_italic_p)
2883 atfm = synthetic_italic_atfm;
2884 else
2885 atfm = CGAffineTransformIdentity;
2886 if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2887 {
2888 CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2889 CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2890 CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2891 }
2892 if (no_antialias_p)
2893 CGContextSetShouldAntialias (context, false);
2894
2895 CGContextSetTextMatrix (context, atfm);
2896 CGContextSetTextPosition (context, text_position.x, text_position.y);
2897
2898 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2899 if (macfont_info->color_bitmap_p
2900 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2901 && CTFontDrawGlyphs != NULL
2902 #endif
2903 )
2904 {
2905 if (len > 0)
2906 {
2907 CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2908 context);
2909 }
2910 }
2911 else
2912 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2913 {
2914 CGContextSetFont (context, macfont_info->cgfont);
2915 CGContextSetFontSize (context, font_size);
2916 CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2917 }
2918 }
2919
2920
2921 xfree (glyphs);
2922 xfree (positions);
2923 CGContextRestoreGState (context);
2924
2925 unblock_input ();
2926
2927 return len;
2928 }
2929
2930 static Lisp_Object
2931 macfont_shape (Lisp_Object lgstring)
2932 {
2933 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2934 struct macfont_info *macfont_info = (struct macfont_info *) font;
2935 CTFontRef macfont = macfont_info->macfont;
2936 ptrdiff_t glyph_len, len, i, j;
2937 CFIndex nonbmp_len;
2938 UniChar *unichars;
2939 CFIndex *nonbmp_indices;
2940 CFStringRef string;
2941 CFIndex used = 0;
2942 struct mac_glyph_layout *glyph_layouts;
2943
2944 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2945 nonbmp_len = 0;
2946 for (i = 0; i < glyph_len; i++)
2947 {
2948 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2949
2950 if (NILP (lglyph))
2951 break;
2952 if (LGLYPH_CHAR (lglyph) >= 0x10000)
2953 nonbmp_len++;
2954 }
2955
2956 len = i;
2957
2958 if (INT_MAX / 2 < len)
2959 memory_full (SIZE_MAX);
2960
2961 unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2962 nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2963 for (i = j = 0; i < len; i++)
2964 {
2965 UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2966
2967 if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2968 {
2969 nonbmp_indices[j] = i + j;
2970 j++;
2971 }
2972 }
2973 nonbmp_indices[j] = len + j; /* sentinel */
2974
2975 block_input ();
2976
2977 string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2978 kCFAllocatorNull);
2979 if (string)
2980 {
2981 glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2982 if (macfont_info->screen_font)
2983 used = mac_screen_font_shape (macfont_info->screen_font, string,
2984 glyph_layouts, glyph_len);
2985 else
2986 used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2987 CFRelease (string);
2988 }
2989
2990 unblock_input ();
2991
2992 if (used == 0)
2993 return Qnil;
2994
2995 block_input ();
2996
2997 for (i = 0; i < used; i++)
2998 {
2999 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
3000 struct mac_glyph_layout *gl = glyph_layouts + i;
3001 EMACS_INT from, to;
3002 struct font_metrics metrics;
3003 int xoff, yoff, wadjust;
3004
3005 if (NILP (lglyph))
3006 {
3007 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
3008 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
3009 }
3010
3011 from = gl->comp_range.location;
3012 /* Convert UTF-16 index to UTF-32. */
3013 j = 0;
3014 while (nonbmp_indices[j] < from)
3015 j++;
3016 from -= j;
3017 LGLYPH_SET_FROM (lglyph, from);
3018
3019 to = gl->comp_range.location + gl->comp_range.length;
3020 /* Convert UTF-16 index to UTF-32. */
3021 while (nonbmp_indices[j] < to)
3022 j++;
3023 to -= j;
3024 LGLYPH_SET_TO (lglyph, to - 1);
3025
3026 /* LGLYPH_CHAR is used in `describe-char' for checking whether
3027 the composition is trivial. */
3028 {
3029 UTF32Char c;
3030
3031 if (unichars[gl->string_index] >= 0xD800
3032 && unichars[gl->string_index] < 0xDC00)
3033 c = (((unichars[gl->string_index] - 0xD800) << 10)
3034 + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3035 else
3036 c = unichars[gl->string_index];
3037 if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3038 c = 0;
3039 LGLYPH_SET_CHAR (lglyph, c);
3040 }
3041
3042 {
3043 unsigned long cc = gl->glyph_id;
3044 LGLYPH_SET_CODE (lglyph, cc);
3045 }
3046
3047 macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3048 LGLYPH_SET_WIDTH (lglyph, metrics.width);
3049 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3050 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3051 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3052 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3053
3054 xoff = lround (gl->advance_delta);
3055 yoff = lround (- gl->baseline_delta);
3056 wadjust = lround (gl->advance);
3057 if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3058 {
3059 Lisp_Object vec;
3060
3061 vec = Fmake_vector (make_number (3), Qnil);
3062 ASET (vec, 0, make_number (xoff));
3063 ASET (vec, 1, make_number (yoff));
3064 ASET (vec, 2, make_number (wadjust));
3065 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3066 }
3067 }
3068
3069 unblock_input ();
3070
3071 return make_number (used);
3072 }
3073
3074 /* Structures for the UVS subtable (format 14) in the cmap table. */
3075 typedef UInt8 UINT24[3];
3076
3077 #pragma pack(push, 1)
3078 struct variation_selector_record
3079 {
3080 UINT24 var_selector;
3081 UInt32 default_uvs_offset, non_default_uvs_offset;
3082 };
3083 struct uvs_table
3084 {
3085 UInt16 format;
3086 UInt32 length, num_var_selector_records;
3087 struct variation_selector_record variation_selector_records[1];
3088 };
3089 #define SIZEOF_UVS_TABLE_HEADER \
3090 (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3091
3092 struct unicode_value_range
3093 {
3094 UINT24 start_unicode_value;
3095 UInt8 additional_count;
3096 };
3097 struct default_uvs_table {
3098 UInt32 num_unicode_value_ranges;
3099 struct unicode_value_range unicode_value_ranges[1];
3100 };
3101 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3102 (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3103
3104 struct uvs_mapping
3105 {
3106 UINT24 unicode_value;
3107 UInt16 glyph_id;
3108 };
3109 struct non_default_uvs_table
3110 {
3111 UInt32 num_uvs_mappings;
3112 struct uvs_mapping uvs_mappings[1];
3113 };
3114 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3115 (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3116 #pragma pack(pop)
3117
3118 /* Read big endian values. The argument LVAL must be an lvalue. */
3119 /* I suppose OSReadBigInt* takes care of unaligned data. At least, we
3120 can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3121 OSReadBigInt16(cdb, 7);" in a sample code by Apple. */
3122 #define BUINT8_VALUE(lval) (*((UInt8 *) &(lval)))
3123 #define BUINT16_VALUE(lval) OSReadBigInt16 (&(lval), 0)
3124 /* Succeeding one byte should also be accessible. */
3125 #define BUINT24_VALUE(lval) (OSReadBigInt32 (&(lval), 0) >> 8)
3126 #define BUINT32_VALUE(lval) OSReadBigInt32 (&(lval), 0)
3127
3128 /* Return UVS subtable for the specified FONT. If the subtable is not
3129 found or ill-formatted, then return NULL. */
3130
3131 static CFDataRef
3132 mac_font_copy_uvs_table (CTFontRef font)
3133 {
3134 CFDataRef cmap_table, uvs_table = NULL;
3135
3136 cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3137 kCTFontTableOptionNoOptions);
3138 if (cmap_table)
3139 {
3140 sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3141 struct uvs_table *uvs;
3142 struct variation_selector_record *records;
3143 UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3144
3145 #if __LP64__
3146 if (CFDataGetLength (cmap_table) > UINT32_MAX)
3147 goto finish;
3148 #endif
3149
3150 cmap_len = CFDataGetLength (cmap_table);
3151 if (sizeof_sfntCMapHeader > cmap_len)
3152 goto finish;
3153
3154 ntables = BUINT16_VALUE (cmap->numTables);
3155 if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3156 / sizeof_sfntCMapEncoding))
3157 goto finish;
3158
3159 for (i = 0; i < ntables; i++)
3160 if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3161 == kFontUnicodePlatform)
3162 && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3163 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3164 {
3165 uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3166 break;
3167 }
3168 if (i == ntables
3169 || uvs_offset > cmap_len
3170 || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3171 goto finish;
3172
3173 uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3174 uvs_len = BUINT32_VALUE (uvs->length);
3175 if (uvs_len > cmap_len - uvs_offset
3176 || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3177 goto finish;
3178
3179 if (BUINT16_VALUE (uvs->format) != 14)
3180 goto finish;
3181
3182 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3183 if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3184 / sizeof (struct variation_selector_record)))
3185 goto finish;
3186
3187 records = uvs->variation_selector_records;
3188 for (i = 0; i < nrecords; i++)
3189 {
3190 UInt32 default_uvs_offset, non_default_uvs_offset;
3191
3192 default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3193 if (default_uvs_offset)
3194 {
3195 struct default_uvs_table *default_uvs;
3196 UInt32 nranges;
3197
3198 if (default_uvs_offset > uvs_len
3199 || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3200 > uvs_len - default_uvs_offset))
3201 goto finish;
3202
3203 default_uvs = ((struct default_uvs_table *)
3204 ((UInt8 *) uvs + default_uvs_offset));
3205 nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3206 if (nranges > ((uvs_len - default_uvs_offset
3207 - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3208 / sizeof (struct unicode_value_range)))
3209 goto finish;
3210 /* Now 2 * nranges can't overflow, so we can safely use
3211 `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3212 mac_font_get_glyphs_for_variants. */
3213 }
3214
3215 non_default_uvs_offset =
3216 BUINT32_VALUE (records[i].non_default_uvs_offset);
3217 if (non_default_uvs_offset)
3218 {
3219 struct non_default_uvs_table *non_default_uvs;
3220 UInt32 nmappings;
3221
3222 if (non_default_uvs_offset > uvs_len
3223 || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3224 > uvs_len - non_default_uvs_offset))
3225 goto finish;
3226
3227 non_default_uvs = ((struct non_default_uvs_table *)
3228 ((UInt8 *) uvs + non_default_uvs_offset));
3229 nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3230 if (nmappings > ((uvs_len - non_default_uvs_offset
3231 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3232 / sizeof (struct uvs_mapping)))
3233 goto finish;
3234 /* Now 2 * nmappings can't overflow, so we can safely
3235 use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3236 in mac_font_get_glyphs_for_variants. */
3237 }
3238 }
3239
3240 uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3241
3242 finish:
3243 CFRelease (cmap_table);
3244 }
3245
3246 return uvs_table;
3247 }
3248
3249 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3250 sequence consisting of the given base character C and each
3251 variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3252 result (explained below) into the corresponding GLYPHS[i]. If the
3253 entry is found in the Default UVS Table, then the result is 0. If
3254 the entry is found in the Non-Default UVS Table, then the result is
3255 the associated glyph ID. Otherwise, kCGFontIndexInvalid. The
3256 elements in SELECTORS must be sorted in strictly increasing
3257 order. */
3258
3259 static void
3260 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3261 const UTF32Char selectors[], CGGlyph glyphs[],
3262 CFIndex count)
3263 {
3264 struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3265 struct variation_selector_record *records = uvs->variation_selector_records;
3266 CFIndex i;
3267 UInt32 ir, nrecords;
3268 dispatch_queue_t queue =
3269 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3270 dispatch_group_t group = dispatch_group_create ();
3271
3272 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3273 i = 0;
3274 ir = 0;
3275 while (i < count && ir < nrecords)
3276 {
3277 UInt32 default_uvs_offset, non_default_uvs_offset;
3278
3279 if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3280 {
3281 glyphs[i++] = kCGFontIndexInvalid;
3282 continue;
3283 }
3284 else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3285 {
3286 ir++;
3287 continue;
3288 }
3289
3290 /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3291 default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3292 non_default_uvs_offset =
3293 BUINT32_VALUE (records[ir].non_default_uvs_offset);
3294 dispatch_group_async (group, queue, ^{
3295 glyphs[i] = kCGFontIndexInvalid;
3296
3297 if (default_uvs_offset)
3298 {
3299 struct default_uvs_table *default_uvs =
3300 (struct default_uvs_table *) ((UInt8 *) uvs
3301 + default_uvs_offset);
3302 struct unicode_value_range *ranges =
3303 default_uvs->unicode_value_ranges;
3304 UInt32 lo, hi;
3305
3306 lo = 0;
3307 hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3308 while (lo < hi)
3309 {
3310 UInt32 mid = (lo + hi) / 2;
3311
3312 if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3313 hi = mid;
3314 else
3315 lo = mid + 1;
3316 }
3317 if (hi > 0
3318 && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3319 + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3320 glyphs[i] = 0;
3321 }
3322
3323 if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3324 {
3325 struct non_default_uvs_table *non_default_uvs =
3326 (struct non_default_uvs_table *) ((UInt8 *) uvs
3327 + non_default_uvs_offset);
3328 struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3329 UInt32 lo, hi;
3330
3331 lo = 0;
3332 hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3333 while (lo < hi)
3334 {
3335 UInt32 mid = (lo + hi) / 2;
3336
3337 if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3338 hi = mid;
3339 else
3340 lo = mid + 1;
3341 }
3342 if (hi > 0 &&
3343 BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3344 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3345 }
3346 });
3347 i++;
3348 ir++;
3349 }
3350 while (i < count)
3351 glyphs[i++] = kCGFontIndexInvalid;
3352 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3353 dispatch_release (group);
3354 }
3355
3356 static int
3357 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3358 {
3359 CFDataRef uvs_table;
3360 CTCharacterCollection uvs_collection;
3361 int i, n = 0;
3362
3363 block_input ();
3364 uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3365
3366 if (uvs_table)
3367 {
3368 UTF32Char selectors[256];
3369 CGGlyph glyphs[256];
3370
3371 for (i = 0; i < 16; i++)
3372 selectors[i] = 0xFE00 + i;
3373 for (; i < 256; i++)
3374 selectors[i] = 0xE0100 + (i - 16);
3375 mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3376 for (i = 0; i < 256; i++)
3377 {
3378 CGGlyph glyph = glyphs[i];
3379
3380 if (uvs_collection != kCTCharacterCollectionIdentityMapping
3381 && glyph != kCGFontIndexInvalid)
3382 glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3383 if (glyph == kCGFontIndexInvalid)
3384 variations[i] = 0;
3385 else
3386 {
3387 variations[i] = (glyph ? glyph
3388 : macfont_get_glyph_for_character (font, c));
3389 n++;
3390 }
3391 }
3392 }
3393 unblock_input ();
3394
3395 return n;
3396 }
3397
3398 static const char *const macfont_booleans[] = {
3399 ":antialias",
3400 ":minspace",
3401 NULL,
3402 };
3403
3404 static const char *const macfont_non_booleans[] = {
3405 ":lang",
3406 ":script",
3407 ":destination",
3408 NULL,
3409 };
3410
3411 static void
3412 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3413 {
3414 font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3415 }
3416
3417 static Boolean
3418 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3419 CFArrayRef languages)
3420 {
3421 Boolean result = true;
3422 CFArrayRef desc_languages =
3423 CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3424
3425 if (desc_languages == NULL)
3426 result = false;
3427 else
3428 {
3429 CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3430 CFIndex i, languages_count = CFArrayGetCount (languages);
3431
3432 for (i = 0; i < languages_count; i++)
3433 {
3434 CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3435
3436 if (!CFArrayContainsValue (desc_languages, range, language)
3437 /* PingFang SC contains "zh" and "zh-Hant" as covered
3438 languages, but does not contain "zh-Hans". */
3439 && !(CFEqual (language, CFSTR ("zh-Hans"))
3440 && CFArrayContainsValue (desc_languages, range,
3441 CFSTR ("zh"))))
3442 {
3443 result = false;
3444 break;
3445 }
3446 }
3447 CFRelease (desc_languages);
3448 }
3449
3450 return result;
3451 }
3452
3453 static CFStringRef
3454 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3455 {
3456 CFStringRef result = NULL;
3457 CFStringRef charset_string =
3458 CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3459
3460 if (charset_string && CFStringGetLength (charset_string) > 0)
3461 {
3462 CFStringRef keys[] = {
3463 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3464 kCTLanguageAttributeName
3465 #else
3466 CFSTR ("NSLanguage")
3467 #endif
3468 };
3469 CFTypeRef values[] = {NULL};
3470 CFIndex num_values = 0;
3471 CFArrayRef languages
3472 = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3473
3474 if (languages && CFArrayGetCount (languages) > 0)
3475 {
3476 if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3477 values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3478 else
3479 {
3480 CFCharacterSetRef charset =
3481 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3482
3483 result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3484 }
3485 }
3486 if (result == NULL)
3487 {
3488 CFAttributedStringRef attr_string = NULL;
3489 CTLineRef ctline = NULL;
3490 CFDictionaryRef attrs
3491 = CFDictionaryCreate (NULL, (const void **) keys,
3492 (const void **) values, num_values,
3493 &kCFTypeDictionaryKeyCallBacks,
3494 &kCFTypeDictionaryValueCallBacks);
3495
3496 if (attrs)
3497 {
3498 attr_string = CFAttributedStringCreate (NULL, charset_string,
3499 attrs);
3500 CFRelease (attrs);
3501 }
3502 if (attr_string)
3503 {
3504 ctline = CTLineCreateWithAttributedString (attr_string);
3505 CFRelease (attr_string);
3506 }
3507 if (ctline)
3508 {
3509 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3510 CFIndex i, nruns = CFArrayGetCount (runs);
3511 CTFontRef font;
3512
3513 for (i = 0; i < nruns; i++)
3514 {
3515 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3516 CFDictionaryRef attributes = CTRunGetAttributes (run);
3517 CTFontRef font_in_run;
3518
3519 if (attributes == NULL)
3520 break;
3521 font_in_run =
3522 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3523 if (font_in_run == NULL)
3524 break;
3525 if (i == 0)
3526 font = font_in_run;
3527 else if (!mac_font_equal_in_postscript_name (font,
3528 font_in_run))
3529 break;
3530 }
3531 if (nruns > 0 && i == nruns)
3532 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3533 CFRelease (ctline);
3534 }
3535 }
3536 }
3537
3538 return result;
3539 }
3540
3541 static inline double
3542 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3543 {
3544 return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3545 &glyph, NULL, 1);
3546 }
3547
3548 static inline CGRect
3549 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3550 {
3551 return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3552 &glyph, NULL, 1);
3553 }
3554
3555 static CFArrayRef
3556 mac_font_create_available_families (void)
3557 {
3558 CFMutableArrayRef families = NULL;
3559 CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3560
3561 if (orig_families)
3562 {
3563 CFIndex i, count = CFArrayGetCount (orig_families);
3564
3565 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3566 if (families)
3567 for (i = 0; i < count; i++)
3568 {
3569 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3570
3571 if (!CFStringHasPrefix (family, CFSTR ("."))
3572 && (CTFontManagerCompareFontFamilyNames (family,
3573 CFSTR ("LastResort"),
3574 NULL)
3575 != kCFCompareEqualTo))
3576 CFArrayAppendValue (families, family);
3577 }
3578 CFRelease (orig_families);
3579 }
3580
3581 return families;
3582 }
3583
3584 static Boolean
3585 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3586 {
3587 Boolean result;
3588 CFStringRef name1, name2;
3589
3590 if (font1 == font2)
3591 return true;
3592
3593 result = false;
3594 name1 = CTFontCopyPostScriptName (font1);
3595 if (name1)
3596 {
3597 name2 = CTFontCopyPostScriptName (font2);
3598 if (name2)
3599 {
3600 result = CFEqual (name1, name2);
3601 CFRelease (name2);
3602 }
3603 CFRelease (name1);
3604 }
3605
3606 return result;
3607 }
3608
3609 static CTLineRef
3610 mac_font_create_line_with_string_and_font (CFStringRef string,
3611 CTFontRef macfont)
3612 {
3613 CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3614 CFTypeRef values[] = {NULL, NULL};
3615 CFDictionaryRef attributes = NULL;
3616 CFAttributedStringRef attr_string = NULL;
3617 CTLineRef ctline = NULL;
3618 float float_zero = 0.0f;
3619
3620 values[0] = macfont;
3621 values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3622 if (values[1])
3623 {
3624 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3625 (const void **) values,
3626 ARRAYELTS (keys),
3627 &kCFTypeDictionaryKeyCallBacks,
3628 &kCFTypeDictionaryValueCallBacks);
3629 CFRelease (values[1]);
3630 }
3631 if (attributes)
3632 {
3633 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3634 CFRelease (attributes);
3635 }
3636 if (attr_string)
3637 {
3638 ctline = CTLineCreateWithAttributedString (attr_string);
3639 CFRelease (attr_string);
3640 }
3641 if (ctline)
3642 {
3643 /* Abandon if ctline contains some fonts other than the
3644 specified one. */
3645 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3646 CFIndex i, nruns = CFArrayGetCount (runs);
3647
3648 for (i = 0; i < nruns; i++)
3649 {
3650 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3651 CFDictionaryRef attributes = CTRunGetAttributes (run);
3652 CTFontRef font_in_run;
3653
3654 if (attributes == NULL)
3655 break;
3656 font_in_run =
3657 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3658 if (font_in_run == NULL)
3659 break;
3660 if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3661 break;
3662 }
3663 if (i < nruns)
3664 {
3665 CFRelease (ctline);
3666 ctline = NULL;
3667 }
3668 }
3669
3670 return ctline;
3671 }
3672
3673 static CFIndex
3674 mac_font_shape (CTFontRef font, CFStringRef string,
3675 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3676 {
3677 CFIndex used, result = 0;
3678 CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3679
3680 if (ctline == NULL)
3681 return 0;
3682
3683 used = CTLineGetGlyphCount (ctline);
3684 if (used <= glyph_len)
3685 {
3686 CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3687 CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3688 CGFloat total_advance = 0;
3689 CFIndex total_glyph_count = 0;
3690
3691 for (k = 0; k < ctrun_count; k++)
3692 {
3693 CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3694 CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3695 struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3696 CFRange string_range, comp_range, range;
3697 CFIndex *permutation;
3698
3699 if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3700 permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3701 else
3702 permutation = NULL;
3703
3704 #define RIGHT_TO_LEFT_P permutation
3705
3706 /* Now the `comp_range' member of struct mac_glyph_layout is
3707 temporarily used as a work area such that:
3708 glbuf[i].comp_range.location =
3709 min {compRange[i + 1].location, ...,
3710 compRange[glyph_count - 1].location,
3711 maxRange (stringRangeForCTRun)}
3712 glbuf[i].comp_range.length = maxRange (compRange[i])
3713 where compRange[i] is the range of composed characters
3714 containing i-th glyph. */
3715 string_range = CTRunGetStringRange (ctrun);
3716 min_location = string_range.location + string_range.length;
3717 for (i = 0; i < glyph_count; i++)
3718 {
3719 struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3720 CFIndex glyph_index;
3721 CFRange rng;
3722
3723 if (!RIGHT_TO_LEFT_P)
3724 glyph_index = glyph_count - i - 1;
3725 else
3726 glyph_index = i;
3727 CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3728 &gl->string_index);
3729 rng =
3730 CFStringGetRangeOfComposedCharactersAtIndex (string,
3731 gl->string_index);
3732 gl->comp_range.location = min_location;
3733 gl->comp_range.length = rng.location + rng.length;
3734 if (rng.location < min_location)
3735 min_location = rng.location;
3736 }
3737
3738 /* Fill the `comp_range' member of struct mac_glyph_layout,
3739 and setup a permutation for right-to-left text. */
3740 comp_range = CFRangeMake (string_range.location, 0);
3741 range = CFRangeMake (0, 0);
3742 while (1)
3743 {
3744 struct mac_glyph_layout *gl =
3745 glbuf + range.location + range.length;
3746
3747 if (gl->comp_range.length
3748 > comp_range.location + comp_range.length)
3749 comp_range.length = gl->comp_range.length - comp_range.location;
3750 min_location = gl->comp_range.location;
3751 range.length++;
3752
3753 if (min_location >= comp_range.location + comp_range.length)
3754 {
3755 comp_range.length = min_location - comp_range.location;
3756 for (i = 0; i < range.length; i++)
3757 {
3758 glbuf[range.location + i].comp_range = comp_range;
3759 if (RIGHT_TO_LEFT_P)
3760 permutation[range.location + i] =
3761 range.location + range.length - i - 1;
3762 }
3763
3764 comp_range = CFRangeMake (min_location, 0);
3765 range.location += range.length;
3766 range.length = 0;
3767 if (range.location == glyph_count)
3768 break;
3769 }
3770 }
3771
3772 /* Then fill the remaining members. */
3773 for (range = CFRangeMake (0, 1); range.location < glyph_count;
3774 range.location++)
3775 {
3776 struct mac_glyph_layout *gl;
3777 CGPoint position;
3778
3779 if (!RIGHT_TO_LEFT_P)
3780 gl = glbuf + range.location;
3781 else
3782 {
3783 CFIndex src, dest;
3784
3785 src = glyph_count - 1 - range.location;
3786 dest = permutation[src];
3787 gl = glbuf + dest;
3788 if (src < dest)
3789 {
3790 CFIndex tmp = gl->string_index;
3791
3792 gl->string_index = glbuf[src].string_index;
3793 glbuf[src].string_index = tmp;
3794 }
3795 }
3796 CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3797
3798 CTRunGetPositions (ctrun, range, &position);
3799 gl->advance_delta = position.x - total_advance;
3800 gl->baseline_delta = position.y;
3801 gl->advance = (gl->advance_delta
3802 + CTRunGetTypographicBounds (ctrun, range,
3803 NULL, NULL, NULL));
3804 total_advance += gl->advance;
3805 }
3806
3807 if (RIGHT_TO_LEFT_P)
3808 xfree (permutation);
3809
3810 #undef RIGHT_TO_LEFT_P
3811
3812 total_glyph_count += glyph_count;
3813 }
3814
3815 result = used;
3816 }
3817 CFRelease (ctline);
3818
3819 return result;
3820 }
3821
3822 /* The function below seems to cause a memory leak for the CFString
3823 created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3824 10.6.3. For now, we use the NSGlyphInfo version instead. */
3825 #if USE_CT_GLYPH_INFO
3826 static CGGlyph
3827 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3828 CGFontIndex cid)
3829 {
3830 CGGlyph result = kCGFontIndexInvalid;
3831 UniChar characters[] = {0xfffd};
3832 CFStringRef string;
3833 CFAttributedStringRef attr_string = NULL;
3834 CTLineRef ctline = NULL;
3835
3836 string = CFStringCreateWithCharacters (NULL, characters,
3837 ARRAYELTS (characters));
3838
3839 if (string)
3840 {
3841 CTGlyphInfoRef glyph_info =
3842 CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3843 CFDictionaryRef attributes = NULL;
3844
3845 if (glyph_info)
3846 {
3847 CFStringRef keys[] = {kCTFontAttributeName,
3848 kCTGlyphInfoAttributeName};
3849 CFTypeRef values[] = {font, glyph_info};
3850
3851 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3852 (const void **) values,
3853 ARRAYELTS (keys),
3854 &kCFTypeDictionaryKeyCallBacks,
3855 &kCFTypeDictionaryValueCallBacks);
3856 CFRelease (glyph_info);
3857 }
3858 if (attributes)
3859 {
3860 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3861 CFRelease (attributes);
3862 }
3863 CFRelease (string);
3864 }
3865 if (attr_string)
3866 {
3867 ctline = CTLineCreateWithAttributedString (attr_string);
3868 CFRelease (attr_string);
3869 }
3870 if (ctline)
3871 {
3872 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3873
3874 if (CFArrayGetCount (runs) > 0)
3875 {
3876 CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3877 CFDictionaryRef attributes = CTRunGetAttributes (run);
3878
3879 if (attributes)
3880 {
3881 CTFontRef font_in_run =
3882 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3883
3884 if (font_in_run
3885 && mac_font_equal_in_postscript_name (font_in_run, font))
3886 {
3887 CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3888 if (result >= CTFontGetGlyphCount (font))
3889 result = kCGFontIndexInvalid;
3890 }
3891 }
3892 }
3893 CFRelease (ctline);
3894 }
3895
3896 return result;
3897 }
3898 #endif
3899
3900 static CFArrayRef
3901 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3902 {
3903 CFArrayRef result = NULL;
3904
3905 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3906 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3907 if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3908 #endif
3909 {
3910 CTFontRef user_font =
3911 CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3912
3913 if (user_font)
3914 {
3915 CFArrayRef languages =
3916 CFArrayCreate (NULL, (const void **) &language, 1,
3917 &kCFTypeArrayCallBacks);
3918
3919 if (languages)
3920 {
3921 result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3922 languages);
3923 CFRelease (languages);
3924 }
3925 CFRelease (user_font);
3926 }
3927 }
3928 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3929 else /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3930 #endif
3931 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3932 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3933 {
3934 CFIndex i;
3935
3936 for (i = 0; macfont_language_default_font_names[i].language; i++)
3937 {
3938 if (CFEqual (macfont_language_default_font_names[i].language,
3939 language))
3940 {
3941 CFMutableArrayRef descriptors =
3942 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3943
3944 if (descriptors)
3945 {
3946 CFIndex j;
3947
3948 for (j = 0;
3949 macfont_language_default_font_names[i].font_names[j];
3950 j++)
3951 {
3952 CFDictionaryRef attributes =
3953 CFDictionaryCreate (NULL,
3954 ((const void **)
3955 &kCTFontNameAttribute),
3956 ((const void **)
3957 &macfont_language_default_font_names[i].font_names[j]),
3958 1, &kCFTypeDictionaryKeyCallBacks,
3959 &kCFTypeDictionaryValueCallBacks);
3960
3961 if (attributes)
3962 {
3963 CTFontDescriptorRef pat_desc =
3964 CTFontDescriptorCreateWithAttributes (attributes);
3965
3966 if (pat_desc)
3967 {
3968 CTFontDescriptorRef descriptor =
3969 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3970
3971 if (descriptor)
3972 {
3973 CFArrayAppendValue (descriptors, descriptor);
3974 CFRelease (descriptor);
3975 }
3976 CFRelease (pat_desc);
3977 }
3978 CFRelease (attributes);
3979 }
3980 }
3981 result = descriptors;
3982 }
3983 break;
3984 }
3985 }
3986 }
3987 #endif
3988
3989 return result;
3990 }
3991
3992 static CFStringRef
3993 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3994 CFArrayRef languages)
3995 {
3996 CFStringRef result = NULL;
3997 CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3998 CFArrayRef descriptors =
3999 mac_font_copy_default_descriptors_for_language (language);
4000
4001 if (descriptors)
4002 {
4003 CFIndex i, count = CFArrayGetCount (descriptors);
4004
4005 for (i = 0; i < count; i++)
4006 {
4007 CTFontDescriptorRef descriptor =
4008 CFArrayGetValueAtIndex (descriptors, i);
4009
4010 if (macfont_supports_charset_and_languages_p (descriptor, charset,
4011 Qnil, languages))
4012 {
4013 CFStringRef family =
4014 CTFontDescriptorCopyAttribute (descriptor,
4015 kCTFontFamilyNameAttribute);
4016 if (family)
4017 {
4018 if (!CFStringHasPrefix (family, CFSTR ("."))
4019 && !CFEqual (family, CFSTR ("LastResort")))
4020 {
4021 result = family;
4022 break;
4023 }
4024 else
4025 CFRelease (family);
4026 }
4027 }
4028 }
4029 CFRelease (descriptors);
4030 }
4031
4032 return result;
4033 }
4034
4035 void *
4036 macfont_get_nsctfont (struct font *font)
4037 {
4038 struct macfont_info *macfont_info = (struct macfont_info *) font;
4039 CTFontRef macfont = macfont_info->macfont;
4040
4041 return (void *) macfont;
4042 }
4043
4044 void
4045 mac_register_font_driver (struct frame *f)
4046 {
4047 register_font_driver (&macfont_driver, f);
4048 }
4049
4050 \f
4051 void
4052 syms_of_macfont (void)
4053 {
4054 /* Core Text, for Mac OS X. */
4055 DEFSYM (Qmac_ct, "mac-ct");
4056 macfont_driver.type = Qmac_ct;
4057 register_font_driver (&macfont_driver, NULL);
4058
4059 /* The font property key specifying the font design destination. The
4060 value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4061 text. (See the documentation of X Logical Font Description
4062 Conventions.) In the Mac font driver, 1 means the screen font is
4063 used for calculating some glyph metrics. You can see the
4064 difference with Monaco 8pt or 9pt, for example. */
4065 DEFSYM (QCdestination, ":destination");
4066
4067 /* The boolean-valued font property key specifying the use of leading. */
4068 DEFSYM (QCminspace, ":minspace");
4069
4070 macfont_family_cache = Qnil;
4071 staticpro (&macfont_family_cache);
4072 }