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