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