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