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