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