]> code.delx.au - gnu-emacs/blob - src/macfont.m
* src/macfont.m (macfont_create_family_with_symbol): Accept localized names.
[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 CFDictionaryRef attributes = NULL;
1042 FontDescriptorRef pat_desc = NULL;
1043
1044 if (macfont_get_family_cache_if_present (symbol, &result))
1045 return result ? CFRetain (result) : NULL;
1046
1047 family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1048 if (family_name)
1049 {
1050 attributes =
1051 CFDictionaryCreate (NULL,
1052 (const void **) &MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1053 (const void **) &family_name, 1,
1054 &kCFTypeDictionaryKeyCallBacks,
1055 &kCFTypeDictionaryValueCallBacks);
1056 CFRelease (family_name);
1057 }
1058 if (attributes)
1059 {
1060 pat_desc = mac_font_descriptor_create_with_attributes (attributes);
1061 CFRelease (attributes);
1062 }
1063 if (pat_desc)
1064 {
1065 FontDescriptorRef desc =
1066 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
1067
1068 if (desc)
1069 {
1070 result =
1071 mac_font_descriptor_copy_attribute (desc,
1072 MAC_FONT_FAMILY_NAME_ATTRIBUTE);
1073 CFRelease (desc);
1074 }
1075 macfont_set_family_cache (symbol, result);
1076 CFRelease (pat_desc);
1077 }
1078
1079 return result;
1080 }
1081
1082 #define WIDTH_FRAC_BITS (4)
1083 #define WIDTH_FRAC_SCALE (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1084
1085 struct macfont_metrics
1086 {
1087 unsigned char lbearing_low, rbearing_low;
1088 signed lbearing_high : 4, rbearing_high : 4;
1089 unsigned char ascent_low, descent_low;
1090 signed ascent_high : 4, descent_high : 4;
1091
1092 /* These two members are used for fixed-point representation of
1093 glyph width. The `width_int' member is an integer that is
1094 closest to the width. The `width_frac' member is the fractional
1095 adjustment representing a value in [-.5, .5], multiplied by
1096 WIDTH_FRAC_SCALE. For synthetic monospace fonts, they represent
1097 the advance delta for centering instead of the glyph width. */
1098 signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1099 };
1100
1101 #define METRICS_VALUE(metrics, member) \
1102 (((metrics)->member##_high << 8) | (metrics)->member##_low)
1103 #define METRICS_SET_VALUE(metrics, member, value) \
1104 do {short tmp = (value); (metrics)->member##_low = tmp & 0xff; \
1105 (metrics)->member##_high = tmp >> 8;} while (0)
1106
1107 enum metrics_status
1108 {
1109 METRICS_INVALID = -1, /* metrics entry is invalid */
1110 METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1111 };
1112
1113 #define METRICS_STATUS(metrics) \
1114 (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1115 #define METRICS_SET_STATUS(metrics, status) \
1116 do {METRICS_SET_VALUE (metrics, ascent, 0); \
1117 METRICS_SET_VALUE (metrics, descent, status);} while (0)
1118
1119 #define METRICS_NCOLS_PER_ROW (128)
1120 #define LCD_FONT_SMOOTHING_LEFT_MARGIN (0.396f)
1121 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1122
1123 static int
1124 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1125 struct font_metrics *metrics, CGFloat *advance_delta,
1126 int force_integral_p)
1127 {
1128 struct macfont_info *macfont_info = (struct macfont_info *) font;
1129 FontRef macfont = macfont_info->macfont;
1130 int row, col;
1131 struct macfont_metrics *cache;
1132 int width;
1133
1134 row = glyph / METRICS_NCOLS_PER_ROW;
1135 col = glyph % METRICS_NCOLS_PER_ROW;
1136 if (row >= macfont_info->metrics_nrows)
1137 {
1138 macfont_info->metrics =
1139 xrealloc (macfont_info->metrics,
1140 sizeof (struct macfont_metrics *) * (row + 1));
1141 memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1142 (sizeof (struct macfont_metrics *)
1143 * (row + 1 - macfont_info->metrics_nrows)));
1144 macfont_info->metrics_nrows = row + 1;
1145 }
1146 if (macfont_info->metrics[row] == NULL)
1147 {
1148 struct macfont_metrics *new;
1149 int i;
1150
1151 new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1152 for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1153 METRICS_SET_STATUS (new + i, METRICS_INVALID);
1154 macfont_info->metrics[row] = new;
1155 }
1156 cache = macfont_info->metrics[row] + col;
1157
1158 if (METRICS_STATUS (cache) == METRICS_INVALID)
1159 {
1160 CGFloat fwidth;
1161
1162 if (macfont_info->screen_font)
1163 fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1164 else
1165 fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1166
1167 /* For synthetic mono fonts, cache->width_{int,frac} holds the
1168 advance delta value. */
1169 if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1170 fwidth = (font->pixel_size - fwidth) / 2;
1171 cache->width_int = lround (fwidth);
1172 cache->width_frac = lround ((fwidth - cache->width_int)
1173 * WIDTH_FRAC_SCALE);
1174 METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1175 }
1176 if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1177 width = font->pixel_size;
1178 else
1179 width = cache->width_int;
1180
1181 if (metrics)
1182 {
1183 if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1184 {
1185 CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1186
1187 if (macfont_info->synthetic_italic_p)
1188 {
1189 /* We assume the members a, b, c, and d in
1190 synthetic_italic_atfm are non-negative. */
1191 bounds.origin =
1192 CGPointApplyAffineTransform (bounds.origin,
1193 synthetic_italic_atfm);
1194 bounds.size =
1195 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1196 }
1197 if (macfont_info->synthetic_bold_p && ! force_integral_p)
1198 {
1199 CGFloat d =
1200 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1201
1202 bounds = CGRectInset (bounds, d, d);
1203 }
1204 switch (macfont_info->spacing)
1205 {
1206 case MACFONT_SPACING_PROPORTIONAL:
1207 bounds.origin.x += - (cache->width_frac
1208 / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1209 break;
1210 case MACFONT_SPACING_MONO:
1211 break;
1212 case MACFONT_SPACING_SYNTHETIC_MONO:
1213 bounds.origin.x += (cache->width_int
1214 + (cache->width_frac
1215 / (CGFloat) WIDTH_FRAC_SCALE));
1216 break;
1217 }
1218 if (bounds.size.width > 0)
1219 {
1220 bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1221 bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1222 + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1223 }
1224 bounds = CGRectIntegral (bounds);
1225 METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1226 METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1227 METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1228 METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1229 }
1230 metrics->lbearing = METRICS_VALUE (cache, lbearing);
1231 metrics->rbearing = METRICS_VALUE (cache, rbearing);
1232 metrics->width = width;
1233 metrics->ascent = METRICS_VALUE (cache, ascent);
1234 metrics->descent = METRICS_VALUE (cache, descent);
1235 }
1236
1237 if (advance_delta)
1238 {
1239 switch (macfont_info->spacing)
1240 {
1241 case MACFONT_SPACING_PROPORTIONAL:
1242 *advance_delta = (force_integral_p ? 0
1243 : - (cache->width_frac
1244 / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1245 break;
1246 case MACFONT_SPACING_MONO:
1247 *advance_delta = 0;
1248 break;
1249 case MACFONT_SPACING_SYNTHETIC_MONO:
1250 *advance_delta = (force_integral_p ? cache->width_int
1251 : (cache->width_int
1252 + (cache->width_frac
1253 / (CGFloat) WIDTH_FRAC_SCALE)));
1254 break;
1255 }
1256 }
1257
1258 return width;
1259 }
1260
1261 static CFMutableDictionaryRef macfont_cache_dictionary;
1262
1263 /* Threshold used in row_nkeys_or_perm. This must be less than or
1264 equal to the number of rows that are invalid as BMP (i.e., from
1265 U+D800 to U+DFFF). */
1266 #define ROW_PERM_OFFSET (8)
1267
1268 /* The number of glyphs that can be stored in a value for a single
1269 entry of CFDictionary. */
1270 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1271
1272 struct macfont_cache
1273 {
1274 int reference_count;
1275 CFCharacterSetRef cf_charset;
1276 struct {
1277 /* The cached glyph for a BMP character c is stored in
1278 matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1279 if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET. */
1280 unsigned char row_nkeys_or_perm[256];
1281 CGGlyph **matrix;
1282
1283 /* Number of rows for which the BMP cache is allocated so far.
1284 I.e., matrix[0] ... matrix[nrows - 1] are non-NULL. */
1285 int nrows;
1286
1287 /* The cached glyph for a character c is stored as the (c %
1288 NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1289 NGLYPHS_IN_VALUE). However, the glyph for a BMP character c is
1290 not stored here if row_nkeys_or_perm[c / 256] >=
1291 ROW_PERM_OFFSET. */
1292 CFMutableDictionaryRef dictionary;
1293 } glyph;
1294
1295 struct {
1296 /* UVS (Unicode Variation Sequence) subtable data, which is of
1297 type CFDataRef if available. NULL means it is not initialized
1298 yet. kCFNull means the subtable is not found and there is no
1299 suitable fallback table for this font. */
1300 CFTypeRef table;
1301
1302 /* Character collection specifying the destination of the mapping
1303 provided by `table' above. If `table' is obtained from the UVS
1304 subtable in the font cmap table, then the value of this member
1305 should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING. */
1306 CharacterCollection collection;
1307 } uvs;
1308 };
1309
1310 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1311 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1312 static void macfont_release_cache (struct macfont_cache *);
1313 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1314 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1315 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1316 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1317 CharacterCollection, CGFontIndex);
1318 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1319
1320 static struct macfont_cache *
1321 macfont_lookup_cache (CFStringRef key)
1322 {
1323 struct macfont_cache *cache;
1324
1325 if (macfont_cache_dictionary == NULL)
1326 {
1327 macfont_cache_dictionary =
1328 CFDictionaryCreateMutable (NULL, 0,
1329 &kCFTypeDictionaryKeyCallBacks, NULL);
1330 cache = NULL;
1331 }
1332 else
1333 cache = ((struct macfont_cache *)
1334 CFDictionaryGetValue (macfont_cache_dictionary, key));
1335
1336 if (cache == NULL)
1337 {
1338 FontRef macfont = mac_font_create_with_name (key, 0);
1339
1340 if (macfont)
1341 {
1342 cache = xzalloc (sizeof (struct macfont_cache));
1343 /* Treat the LastResort font as if it contained glyphs for
1344 all characters. This may look too rough, but neither
1345 CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1346 for this font is correct for non-BMP characters on Mac OS
1347 X 10.5, anyway. */
1348 if (CFEqual (key, CFSTR ("LastResort")))
1349 {
1350 CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1351
1352 cache->cf_charset =
1353 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1354 }
1355 if (cache->cf_charset == NULL)
1356 cache->cf_charset = mac_font_copy_character_set (macfont);
1357 CFDictionaryAddValue (macfont_cache_dictionary, key,
1358 (const void *) cache);
1359 CFRelease (macfont);
1360 }
1361 }
1362
1363 return cache;
1364 }
1365
1366 static struct macfont_cache *
1367 macfont_retain_cache (struct macfont_cache *cache)
1368 {
1369 cache->reference_count++;
1370
1371 return cache;
1372 }
1373
1374 static void
1375 macfont_release_cache (struct macfont_cache *cache)
1376 {
1377 if (--cache->reference_count == 0)
1378 {
1379 int i;
1380
1381 for (i = 0; i < cache->glyph.nrows; i++)
1382 xfree (cache->glyph.matrix[i]);
1383 xfree (cache->glyph.matrix);
1384 if (cache->glyph.dictionary)
1385 CFRelease (cache->glyph.dictionary);
1386 memset (&cache->glyph, 0, sizeof (cache->glyph));
1387 if (cache->uvs.table)
1388 CFRelease (cache->uvs.table);
1389 memset (&cache->uvs, 0, sizeof (cache->uvs));
1390 }
1391 }
1392
1393 static CFCharacterSetRef
1394 macfont_get_cf_charset (struct font *font)
1395 {
1396 struct macfont_info *macfont_info = (struct macfont_info *) font;
1397
1398 return macfont_info->cache->cf_charset;
1399 }
1400
1401 static CFCharacterSetRef
1402 macfont_get_cf_charset_for_name (CFStringRef name)
1403 {
1404 struct macfont_cache *cache = macfont_lookup_cache (name);
1405
1406 return cache->cf_charset;
1407 }
1408
1409 static CGGlyph
1410 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1411 {
1412 struct macfont_info *macfont_info = (struct macfont_info *) font;
1413 FontRef macfont = macfont_info->macfont;
1414 struct macfont_cache *cache = macfont_info->cache;
1415
1416 if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1417 {
1418 int row = c / 256;
1419 int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1420
1421 if (nkeys_or_perm < ROW_PERM_OFFSET)
1422 {
1423 UniChar unichars[256], ch;
1424 CGGlyph *glyphs;
1425 int i, len;
1426 int nrows;
1427 dispatch_queue_t queue;
1428 dispatch_group_t group = NULL;
1429
1430 if (row != 0)
1431 {
1432 CFMutableDictionaryRef dictionary;
1433 uintptr_t key, value;
1434 int nshifts;
1435 CGGlyph glyph;
1436
1437 if (cache->glyph.dictionary == NULL)
1438 cache->glyph.dictionary =
1439 CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1440 dictionary = cache->glyph.dictionary;
1441 key = c / NGLYPHS_IN_VALUE;
1442 nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1443 value = ((uintptr_t)
1444 CFDictionaryGetValue (dictionary, (const void *) key));
1445 glyph = (value >> nshifts);
1446 if (glyph)
1447 return glyph;
1448
1449 if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1450 {
1451 ch = c;
1452 if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1453 &glyph, 1)
1454 || glyph == 0)
1455 glyph = kCGFontIndexInvalid;
1456
1457 if (value == 0)
1458 cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1459 value |= ((uintptr_t) glyph << nshifts);
1460 CFDictionarySetValue (dictionary, (const void *) key,
1461 (const void *) value);
1462
1463 return glyph;
1464 }
1465
1466 queue =
1467 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1468 group = dispatch_group_create ();
1469 dispatch_group_async (group, queue, ^{
1470 int nkeys;
1471 uintptr_t key;
1472 nkeys = nkeys_or_perm;
1473 for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1474 if (CFDictionaryContainsKey (dictionary,
1475 (const void *) key))
1476 {
1477 CFDictionaryRemoveValue (dictionary,
1478 (const void *) key);
1479 if (--nkeys == 0)
1480 break;
1481 }
1482 });
1483 }
1484
1485 len = 0;
1486 for (i = 0; i < 256; i++)
1487 {
1488 ch = row * 256 + i;
1489 if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1490 unichars[len++] = ch;
1491 }
1492
1493 glyphs = xmalloc (sizeof (CGGlyph) * 256);
1494 if (len > 0)
1495 {
1496 mac_font_get_glyphs_for_characters (macfont, unichars,
1497 glyphs, len);
1498 while (i > len)
1499 {
1500 int next = unichars[len - 1] % 256;
1501
1502 while (--i > next)
1503 glyphs[i] = kCGFontIndexInvalid;
1504
1505 len--;
1506 glyphs[i] = glyphs[len];
1507 if (len == 0)
1508 break;
1509 }
1510 }
1511 if (i > len)
1512 while (i-- > 0)
1513 glyphs[i] = kCGFontIndexInvalid;
1514
1515 nrows = cache->glyph.nrows;
1516 nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1517 cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1518 nrows++;
1519 cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1520 sizeof (CGGlyph *) * nrows);
1521 cache->glyph.matrix[nrows - 1] = glyphs;
1522 cache->glyph.nrows = nrows;
1523
1524 if (group)
1525 {
1526 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1527 dispatch_release (group);
1528 }
1529 }
1530
1531 return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1532 }
1533 else
1534 {
1535 uintptr_t key, value;
1536 int nshifts;
1537 CGGlyph glyph;
1538
1539 if (cache->glyph.dictionary == NULL)
1540 cache->glyph.dictionary =
1541 CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1542 key = c / NGLYPHS_IN_VALUE;
1543 nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1544 value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1545 (const void *) key);
1546 glyph = (value >> nshifts);
1547 if (glyph == 0)
1548 {
1549 UniChar unichars[2];
1550 CGGlyph glyphs[2];
1551 CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1552
1553 if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1554 count))
1555 glyph = glyphs[0];
1556 if (glyph == 0)
1557 glyph = kCGFontIndexInvalid;
1558
1559 value |= ((uintptr_t) glyph << nshifts);
1560 CFDictionarySetValue (cache->glyph.dictionary,
1561 (const void *) key, (const void *) value);
1562 }
1563
1564 return glyph;
1565 }
1566 }
1567
1568 static CGGlyph
1569 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1570 CGFontIndex cid)
1571 {
1572 struct macfont_info *macfont_info = (struct macfont_info *) font;
1573 FontRef macfont = macfont_info->macfont;
1574
1575 /* Cache it? */
1576 return mac_font_get_glyph_for_cid (macfont, collection, cid);
1577 }
1578
1579 static CFDataRef
1580 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1581 {
1582 struct macfont_info *macfont_info = (struct macfont_info *) font;
1583 FontRef macfont = macfont_info->macfont;
1584 struct macfont_cache *cache = macfont_info->cache;
1585 CFDataRef result = NULL;
1586
1587 if (cache->uvs.table == NULL)
1588 {
1589 CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1590 CharacterCollection uvs_collection =
1591 MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1592
1593 if (uvs_table == NULL
1594 && mac_font_get_glyph_for_cid (macfont,
1595 MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1596 6480) != kCGFontIndexInvalid)
1597 {
1598 /* If the glyph for U+4E55 is accessible via its CID 6480,
1599 then we use the Adobe-Japan1 UVS table, which maps a
1600 variation sequence to a CID, as a fallback. */
1601 static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1602
1603 if (mac_uvs_table_adobe_japan1 == NULL)
1604 mac_uvs_table_adobe_japan1 =
1605 CFDataCreateWithBytesNoCopy (NULL,
1606 mac_uvs_table_adobe_japan1_bytes,
1607 sizeof (mac_uvs_table_adobe_japan1_bytes),
1608 kCFAllocatorNull);
1609 if (mac_uvs_table_adobe_japan1)
1610 {
1611 uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1612 uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1613 }
1614 }
1615 if (uvs_table == NULL)
1616 cache->uvs.table = kCFNull;
1617 else
1618 cache->uvs.table = uvs_table;
1619 cache->uvs.collection = uvs_collection;
1620 }
1621
1622 if (cache->uvs.table != kCFNull)
1623 {
1624 result = cache->uvs.table;
1625 *collection = cache->uvs.collection;
1626 }
1627
1628 return result;
1629 }
1630
1631 static Lisp_Object macfont_get_cache (struct frame *);
1632 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1633 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1634 static Lisp_Object macfont_list_family (struct frame *);
1635 static void macfont_free_entity (Lisp_Object);
1636 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1637 static void macfont_close (struct font *);
1638 static int macfont_has_char (Lisp_Object, int);
1639 static unsigned macfont_encode_char (struct font *, int);
1640 static void macfont_text_extents (struct font *, unsigned int *, int,
1641 struct font_metrics *);
1642 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1643 static Lisp_Object macfont_shape (Lisp_Object);
1644 static int macfont_variation_glyphs (struct font *, int c,
1645 unsigned variations[256]);
1646 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1647
1648 static struct font_driver macfont_driver =
1649 {
1650 LISP_INITIALLY_ZERO, /* Qmac_ct */
1651 0, /* case insensitive */
1652 macfont_get_cache,
1653 macfont_list,
1654 macfont_match,
1655 macfont_list_family,
1656 macfont_free_entity,
1657 macfont_open,
1658 macfont_close,
1659 NULL, /* prepare_face */
1660 NULL, /* done_face */
1661 macfont_has_char,
1662 macfont_encode_char,
1663 macfont_text_extents,
1664 macfont_draw,
1665 NULL, /* get_bitmap */
1666 NULL, /* free_bitmap */
1667 NULL, /* anchor_point */
1668 NULL, /* otf_capability */
1669 NULL, /* otf_drive */
1670 NULL, /* start_for_frame */
1671 NULL, /* end_for_frame */
1672 macfont_shape,
1673 NULL, /* check */
1674 macfont_variation_glyphs,
1675 macfont_filter_properties,
1676 };
1677
1678 static Lisp_Object
1679 macfont_get_cache (struct frame * f)
1680 {
1681 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1682
1683 return (dpyinfo->name_list_element);
1684 }
1685
1686 static int
1687 macfont_get_charset (Lisp_Object registry)
1688 {
1689 char *str = SSDATA (SYMBOL_NAME (registry));
1690 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1691 Lisp_Object regexp;
1692 int i, j;
1693
1694 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1695 {
1696 if (str[i] == '.')
1697 re[j++] = '\\';
1698 else if (str[i] == '*')
1699 re[j++] = '.';
1700 re[j] = str[i];
1701 if (re[j] == '?')
1702 re[j] = '.';
1703 }
1704 re[j] = '\0';
1705 regexp = make_unibyte_string (re, j);
1706 for (i = 0; cf_charset_table[i].name; i++)
1707 if (fast_c_string_match_ignore_case
1708 (regexp, cf_charset_table[i].name,
1709 strlen (cf_charset_table[i].name)) >= 0)
1710 break;
1711 if (! cf_charset_table[i].name)
1712 return -1;
1713 if (! cf_charset_table[i].cf_charset)
1714 {
1715 int *uniquifier = cf_charset_table[i].uniquifier;
1716 UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1717 CFIndex count = 0;
1718 CFStringRef string;
1719 CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1720
1721 if (! charset)
1722 return -1;
1723 for (j = 0; uniquifier[j]; j++)
1724 {
1725 count += macfont_store_utf32char_to_unichars (uniquifier[j],
1726 unichars + count);
1727 CFCharacterSetAddCharactersInRange (charset,
1728 CFRangeMake (uniquifier[j], 1));
1729 }
1730
1731 string = CFStringCreateWithCharacters (NULL, unichars, count);
1732 if (! string)
1733 {
1734 CFRelease (charset);
1735 return -1;
1736 }
1737 cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1738 charset);
1739 CFRelease (charset);
1740 /* CFCharacterSetCreateWithCharactersInString does not handle
1741 surrogate pairs properly as of Mac OS X 10.5. */
1742 cf_charset_table[i].cf_charset_string = string;
1743 }
1744 return i;
1745 }
1746
1747 struct OpenTypeSpec
1748 {
1749 Lisp_Object script;
1750 unsigned int script_tag, langsys_tag;
1751 int nfeatures[2];
1752 unsigned int *features[2];
1753 };
1754
1755 #define OTF_SYM_TAG(SYM, TAG) \
1756 do { \
1757 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
1758 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
1759 } while (0)
1760
1761 #define OTF_TAG_STR(TAG, P) \
1762 do { \
1763 (P)[0] = (char) (TAG >> 24); \
1764 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
1765 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
1766 (P)[3] = (char) (TAG & 0xFF); \
1767 (P)[4] = '\0'; \
1768 } while (0)
1769
1770 static struct OpenTypeSpec *
1771 macfont_get_open_type_spec (Lisp_Object otf_spec)
1772 {
1773 struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1774 Lisp_Object val;
1775 int i, j;
1776 bool negative;
1777
1778 if (! spec)
1779 return NULL;
1780 spec->script = XCAR (otf_spec);
1781 if (! NILP (spec->script))
1782 {
1783 OTF_SYM_TAG (spec->script, spec->script_tag);
1784 val = assq_no_quit (spec->script, Votf_script_alist);
1785 if (CONSP (val) && SYMBOLP (XCDR (val)))
1786 spec->script = XCDR (val);
1787 else
1788 spec->script = Qnil;
1789 }
1790 else
1791 spec->script_tag = 0x44464C54; /* "DFLT" */
1792 otf_spec = XCDR (otf_spec);
1793 spec->langsys_tag = 0;
1794 if (! NILP (otf_spec))
1795 {
1796 val = XCAR (otf_spec);
1797 if (! NILP (val))
1798 OTF_SYM_TAG (val, spec->langsys_tag);
1799 otf_spec = XCDR (otf_spec);
1800 }
1801 spec->nfeatures[0] = spec->nfeatures[1] = 0;
1802 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1803 {
1804 Lisp_Object len;
1805
1806 val = XCAR (otf_spec);
1807 if (NILP (val))
1808 continue;
1809 len = Flength (val);
1810 spec->features[i] =
1811 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1812 ? 0
1813 : malloc (XINT (len) * sizeof *spec->features[i]));
1814 if (! spec->features[i])
1815 {
1816 if (i > 0 && spec->features[0])
1817 free (spec->features[0]);
1818 free (spec);
1819 return NULL;
1820 }
1821 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1822 {
1823 if (NILP (XCAR (val)))
1824 negative = 1;
1825 else
1826 {
1827 unsigned int tag;
1828
1829 OTF_SYM_TAG (XCAR (val), tag);
1830 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1831 }
1832 }
1833 spec->nfeatures[i] = j;
1834 }
1835 return spec;
1836 }
1837
1838 static CFMutableDictionaryRef
1839 macfont_create_attributes_with_spec (Lisp_Object spec)
1840 {
1841 Lisp_Object tmp, extra;
1842 CFMutableArrayRef langarray = NULL;
1843 CFCharacterSetRef charset = NULL;
1844 CFStringRef charset_string = NULL;
1845 CFMutableDictionaryRef attributes = NULL, traits = NULL;
1846 Lisp_Object script = Qnil;
1847 Lisp_Object registry;
1848 int cf_charset_idx, i;
1849 struct OpenTypeSpec *otspec = NULL;
1850 struct {
1851 enum font_property_index index;
1852 CFStringRef trait;
1853 CGPoint points[6];
1854 } numeric_traits[] =
1855 {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1856 {{-0.4, 50}, /* light */
1857 {-0.24, 87.5}, /* (semi-light + normal) / 2 */
1858 {0, 100}, /* normal */
1859 {0.24, 140}, /* (semi-bold + normal) / 2 */
1860 {0.4, 200}, /* bold */
1861 {CGFLOAT_MAX, CGFLOAT_MAX}}},
1862 {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1863 {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1864 {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1865 {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1866
1867 registry = AREF (spec, FONT_REGISTRY_INDEX);
1868 if (NILP (registry)
1869 || EQ (registry, Qascii_0)
1870 || EQ (registry, Qiso10646_1)
1871 || EQ (registry, Qunicode_bmp))
1872 cf_charset_idx = -1;
1873 else
1874 {
1875 CFStringRef lang;
1876
1877 cf_charset_idx = macfont_get_charset (registry);
1878 if (cf_charset_idx < 0)
1879 goto err;
1880 charset = cf_charset_table[cf_charset_idx].cf_charset;
1881 charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1882 lang = cf_charset_table[cf_charset_idx].lang;
1883 if (lang)
1884 {
1885 langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1886 if (! langarray)
1887 goto err;
1888 CFArrayAppendValue (langarray, lang);
1889 }
1890 }
1891
1892 for (extra = AREF (spec, FONT_EXTRA_INDEX);
1893 CONSP (extra); extra = XCDR (extra))
1894 {
1895 Lisp_Object key, val;
1896
1897 tmp = XCAR (extra);
1898 key = XCAR (tmp), val = XCDR (tmp);
1899 if (EQ (key, QClang))
1900 {
1901 if (! langarray)
1902 langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1903 if (! langarray)
1904 goto err;
1905 if (SYMBOLP (val))
1906 val = list1 (val);
1907 for (; CONSP (val); val = XCDR (val))
1908 if (SYMBOLP (XCAR (val)))
1909 {
1910 CFStringRef lang =
1911 cfstring_create_with_string_noencode (SYMBOL_NAME
1912 (XCAR (val)));
1913
1914 if (lang == NULL)
1915 goto err;
1916 CFArrayAppendValue (langarray, lang);
1917 CFRelease (lang);
1918 }
1919 }
1920 else if (EQ (key, QCotf))
1921 {
1922 otspec = macfont_get_open_type_spec (val);
1923 if (! otspec)
1924 goto err;
1925 script = otspec->script;
1926 }
1927 else if (EQ (key, QCscript))
1928 script = val;
1929 }
1930
1931 if (! NILP (script) && ! charset)
1932 {
1933 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1934
1935 if (CONSP (chars) && CONSP (CDR (chars)))
1936 {
1937 CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1938 CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1939
1940 if (! string || !cs)
1941 {
1942 if (string)
1943 CFRelease (string);
1944 else if (cs)
1945 CFRelease (cs);
1946 goto err;
1947 }
1948 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1949 if (CHARACTERP (XCAR (chars)))
1950 {
1951 UniChar unichars[2];
1952 CFIndex count =
1953 macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1954 unichars);
1955 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1956
1957 CFStringAppendCharacters (string, unichars, count);
1958 CFCharacterSetAddCharactersInRange (cs, range);
1959 }
1960 charset = cs;
1961 /* CFCharacterSetCreateWithCharactersInString does not
1962 handle surrogate pairs properly as of Mac OS X 10.5. */
1963 charset_string = string;
1964 }
1965 }
1966
1967 attributes = CFDictionaryCreateMutable (NULL, 0,
1968 &kCFTypeDictionaryKeyCallBacks,
1969 &kCFTypeDictionaryValueCallBacks);
1970 if (! attributes)
1971 goto err;
1972
1973 tmp = AREF (spec, FONT_FAMILY_INDEX);
1974 if (SYMBOLP (tmp) && ! NILP (tmp))
1975 {
1976 CFStringRef family = macfont_create_family_with_symbol (tmp);
1977
1978 if (! family)
1979 goto err;
1980 CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1981 family);
1982 CFRelease (family);
1983 }
1984
1985 traits = CFDictionaryCreateMutable (NULL, 4,
1986 &kCFTypeDictionaryKeyCallBacks,
1987 &kCFTypeDictionaryValueCallBacks);
1988 if (! traits)
1989 goto err;
1990
1991 for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1992 {
1993 tmp = AREF (spec, numeric_traits[i].index);
1994 if (INTEGERP (tmp))
1995 {
1996 CGPoint *point = numeric_traits[i].points;
1997 CGFloat floatval = (XINT (tmp) >> 8); // XXX
1998 CFNumberRef num;
1999
2000 while (point->y < floatval)
2001 point++;
2002 if (point == numeric_traits[i].points)
2003 point++;
2004 else if (point->y == CGFLOAT_MAX)
2005 point--;
2006 floatval = (point - 1)->x + ((floatval - (point - 1)->y)
2007 * ((point->x - (point - 1)->x)
2008 / (point->y - (point - 1)->y)));
2009 if (floatval > 1.0)
2010 floatval = 1.0;
2011 else if (floatval < -1.0)
2012 floatval = -1.0;
2013 num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2014 if (! num)
2015 goto err;
2016 CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2017 CFRelease (num);
2018 }
2019 }
2020 if (CFDictionaryGetCount (traits))
2021 CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
2022
2023 if (charset)
2024 CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
2025 charset);
2026 if (charset_string)
2027 CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2028 charset_string);
2029 if (langarray)
2030 CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
2031
2032 goto finish;
2033
2034 err:
2035 if (attributes)
2036 {
2037 CFRelease (attributes);
2038 attributes = NULL;
2039 }
2040
2041 finish:
2042 if (langarray) CFRelease (langarray);
2043 if (charset && cf_charset_idx < 0) CFRelease (charset);
2044 if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2045 if (traits) CFRelease (traits);
2046 if (otspec)
2047 {
2048 if (otspec->nfeatures[0] > 0)
2049 free (otspec->features[0]);
2050 if (otspec->nfeatures[1] > 0)
2051 free (otspec->features[1]);
2052 free (otspec);
2053 }
2054
2055 return attributes;
2056 }
2057
2058 static Boolean
2059 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
2060 CFCharacterSetRef charset,
2061 Lisp_Object chars,
2062 CFArrayRef languages)
2063 {
2064 Boolean result = true;
2065
2066 if (charset || VECTORP (chars))
2067 {
2068 CFCharacterSetRef desc_charset =
2069 mac_font_descriptor_copy_attribute (desc,
2070 MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2071
2072 if (desc_charset == NULL)
2073 result = false;
2074 else
2075 {
2076 if (charset)
2077 result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2078 else /* VECTORP (chars) */
2079 {
2080 ptrdiff_t j;
2081
2082 for (j = 0; j < ASIZE (chars); j++)
2083 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2084 && CFCharacterSetIsLongCharacterMember (desc_charset,
2085 XFASTINT (AREF (chars, j))))
2086 break;
2087 if (j == ASIZE (chars))
2088 result = false;
2089 }
2090 CFRelease (desc_charset);
2091 }
2092 }
2093 if (result && languages)
2094 result = mac_font_descriptor_supports_languages (desc, languages);
2095
2096 return result;
2097 }
2098
2099 static int
2100 macfont_traits_distance (FontSymbolicTraits sym_traits1,
2101 FontSymbolicTraits sym_traits2)
2102 {
2103 FontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2104 int distance = 0;
2105
2106 /* We prefer synthetic bold of italic to synthetic italic of bold
2107 when both bold and italic are available but bold-italic is not
2108 available. */
2109 if (diff & MAC_FONT_TRAIT_BOLD)
2110 distance |= (1 << 0);
2111 if (diff & MAC_FONT_TRAIT_ITALIC)
2112 distance |= (1 << 1);
2113 if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2114 distance |= (1 << 2);
2115
2116 return distance;
2117 }
2118
2119 static Boolean
2120 macfont_closest_traits_index_p (CFArrayRef traits_array,
2121 FontSymbolicTraits target,
2122 CFIndex index)
2123 {
2124 CFIndex i, count = CFArrayGetCount (traits_array);
2125 FontSymbolicTraits traits;
2126 int my_distance;
2127
2128 traits = ((FontSymbolicTraits) (uintptr_t)
2129 CFArrayGetValueAtIndex (traits_array, index));
2130 my_distance = macfont_traits_distance (target, traits);
2131
2132 for (i = 0; i < count; i++)
2133 if (i != index)
2134 {
2135 traits = ((FontSymbolicTraits) (uintptr_t)
2136 CFArrayGetValueAtIndex (traits_array, i));
2137 if (macfont_traits_distance (target, traits) < my_distance)
2138 return false;
2139 }
2140
2141 return true;
2142 }
2143
2144 static Lisp_Object
2145 macfont_list (struct frame *f, Lisp_Object spec)
2146 {
2147 Lisp_Object val = Qnil, family, extra;
2148 int i, n;
2149 CFStringRef family_name = NULL;
2150 CFMutableDictionaryRef attributes = NULL, traits;
2151 Lisp_Object chars = Qnil;
2152 int spacing = -1;
2153 FontSymbolicTraits synth_sym_traits = 0;
2154 CFArrayRef families;
2155 CFIndex families_count;
2156 CFCharacterSetRef charset = NULL;
2157 CFArrayRef languages = NULL;
2158
2159 block_input ();
2160
2161 family = AREF (spec, FONT_FAMILY_INDEX);
2162 if (! NILP (family))
2163 {
2164 family_name = macfont_create_family_with_symbol (family);
2165 if (family_name == NULL)
2166 goto finish;
2167 }
2168
2169 attributes = macfont_create_attributes_with_spec (spec);
2170 if (! attributes)
2171 goto finish;
2172
2173 languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2174
2175 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2176 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2177
2178 traits = ((CFMutableDictionaryRef)
2179 CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2180
2181 n = FONT_SLANT_NUMERIC (spec);
2182 if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2183 {
2184 synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2185 if (traits)
2186 CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2187 }
2188
2189 n = FONT_WEIGHT_NUMERIC (spec);
2190 if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2191 {
2192 synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2193 if (traits)
2194 CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2195 }
2196
2197 if (languages
2198 && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2199 {
2200 CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2201
2202 if (CFStringHasPrefix (language, CFSTR ("ja"))
2203 || CFStringHasPrefix (language, CFSTR ("ko"))
2204 || CFStringHasPrefix (language, CFSTR ("zh")))
2205 synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2206 }
2207
2208 /* Create array of families. */
2209 if (family_name)
2210 families = CFArrayCreate (NULL, (const void **) &family_name,
2211 1, &kCFTypeArrayCallBacks);
2212 else
2213 {
2214 CFStringRef pref_family;
2215 CFIndex families_count, pref_family_index = -1;
2216
2217 families = macfont_copy_available_families_cache ();
2218 if (families == NULL)
2219 goto err;
2220
2221 families_count = CFArrayGetCount (families);
2222
2223 /* Move preferred family to the front if exists. */
2224 pref_family =
2225 mac_font_create_preferred_family_for_attributes (attributes);
2226 if (pref_family)
2227 {
2228 pref_family_index =
2229 CFArrayGetFirstIndexOfValue (families,
2230 CFRangeMake (0, families_count),
2231 pref_family);
2232 CFRelease (pref_family);
2233 }
2234 if (pref_family_index > 0)
2235 {
2236 CFMutableArrayRef mutable_families =
2237 CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2238
2239 if (mutable_families)
2240 {
2241 CFArrayAppendValue (mutable_families,
2242 CFArrayGetValueAtIndex (families,
2243 pref_family_index));
2244 CFArrayAppendArray (mutable_families, families,
2245 CFRangeMake (0, pref_family_index));
2246 if (pref_family_index + 1 < families_count)
2247 CFArrayAppendArray (mutable_families, families,
2248 CFRangeMake (pref_family_index + 1,
2249 families_count
2250 - (pref_family_index + 1)));
2251 CFRelease (families);
2252 families = mutable_families;
2253 }
2254 }
2255 }
2256
2257 charset = CFDictionaryGetValue (attributes,
2258 MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2259 if (charset)
2260 {
2261 CFRetain (charset);
2262 CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2263 }
2264 else
2265 {
2266 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2267 if (! NILP (val))
2268 {
2269 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2270 if (CONSP (val) && VECTORP (XCDR (val)))
2271 chars = XCDR (val);
2272 }
2273 val = Qnil;
2274 }
2275
2276 if (languages)
2277 {
2278 CFRetain (languages);
2279 CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2280 }
2281
2282 val = Qnil;
2283 extra = AREF (spec, FONT_EXTRA_INDEX);
2284 families_count = CFArrayGetCount (families);
2285 for (i = 0; i < families_count; i++)
2286 {
2287 CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2288 FontDescriptorRef pat_desc;
2289 CFArrayRef descs;
2290 CFIndex descs_count;
2291 CFMutableArrayRef filtered_descs, traits_array;
2292 Lisp_Object entity;
2293 int j;
2294
2295 CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2296 family_name);
2297 pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2298 if (! pat_desc)
2299 goto err;
2300
2301 /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2302 10.7 returns NULL if pat_desc represents the LastResort font.
2303 So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2304 trailing "s") for such a font. */
2305 if (!CFEqual (family_name, CFSTR ("LastResort")))
2306 descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2307 NULL);
2308 else
2309 {
2310 FontDescriptorRef lr_desc =
2311 mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2312 NULL);
2313 if (lr_desc)
2314 {
2315 descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2316 &kCFTypeArrayCallBacks);
2317 CFRelease (lr_desc);
2318 }
2319 else
2320 descs = NULL;
2321 }
2322 CFRelease (pat_desc);
2323 if (! descs)
2324 continue;
2325
2326 descs_count = CFArrayGetCount (descs);
2327 if (descs_count == 0
2328 || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2329 charset, chars,
2330 languages))
2331 {
2332 CFRelease (descs);
2333 continue;
2334 }
2335
2336 filtered_descs =
2337 CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2338 traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2339 for (j = 0; j < descs_count; j++)
2340 {
2341 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2342 CFDictionaryRef dict;
2343 CFNumberRef num;
2344 FontSymbolicTraits sym_traits;
2345
2346 dict = mac_font_descriptor_copy_attribute (desc,
2347 MAC_FONT_TRAITS_ATTRIBUTE);
2348 if (dict == NULL)
2349 continue;
2350
2351 num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2352 CFRelease (dict);
2353 if (num == NULL
2354 || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2355 continue;
2356
2357 if (spacing >= 0
2358 && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2359 && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2360 != (spacing >= FONT_SPACING_MONO)))
2361 continue;
2362
2363 /* Don't use a color bitmap font unless its family is
2364 explicitly specified. */
2365 if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2366 continue;
2367
2368 if (j > 0
2369 && !macfont_supports_charset_and_languages_p (desc, charset,
2370 chars, languages))
2371 continue;
2372
2373 CFArrayAppendValue (filtered_descs, desc);
2374 CFArrayAppendValue (traits_array,
2375 (const void *) (uintptr_t) sym_traits);
2376 }
2377
2378 CFRelease (descs);
2379 descs = filtered_descs;
2380 descs_count = CFArrayGetCount (descs);
2381
2382 for (j = 0; j < descs_count; j++)
2383 {
2384 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2385 FontSymbolicTraits sym_traits =
2386 ((FontSymbolicTraits) (uintptr_t)
2387 CFArrayGetValueAtIndex (traits_array, j));
2388 FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2389
2390 mask_min = ((synth_sym_traits ^ sym_traits)
2391 & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2392 if (FONT_SLANT_NUMERIC (spec) < 0)
2393 mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2394 if (FONT_WEIGHT_NUMERIC (spec) < 0)
2395 mask_min &= ~MAC_FONT_TRAIT_BOLD;
2396
2397 mask_max = (synth_sym_traits & ~sym_traits);
2398 /* Synthetic bold does not work for bitmap-only fonts on Mac
2399 OS X 10.6. */
2400 if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2401 {
2402 CFNumberRef format =
2403 mac_font_descriptor_copy_attribute (desc,
2404 MAC_FONT_FORMAT_ATTRIBUTE);
2405
2406 if (format)
2407 {
2408 uint32_t format_val;
2409
2410 if (CFNumberGetValue (format, kCFNumberSInt32Type,
2411 &format_val)
2412 && format_val == MAC_FONT_FORMAT_BITMAP)
2413 mask_max &= ~MAC_FONT_TRAIT_BOLD;
2414 }
2415 }
2416 if (spacing >= 0)
2417 mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2418
2419 for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2420 mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2421 mmask += MAC_FONT_TRAIT_MONO_SPACE)
2422 for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2423 bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2424 bmask += MAC_FONT_TRAIT_BOLD)
2425 for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2426 imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2427 imask += MAC_FONT_TRAIT_ITALIC)
2428 {
2429 FontSymbolicTraits synth = (imask | bmask | mmask);
2430
2431 if (synth == 0
2432 || macfont_closest_traits_index_p (traits_array,
2433 (sym_traits | synth),
2434 j))
2435 {
2436 entity = macfont_descriptor_entity (desc, extra, synth);
2437 if (! NILP (entity))
2438 val = Fcons (entity, val);
2439 }
2440 }
2441 }
2442
2443 CFRelease (traits_array);
2444 CFRelease (descs);
2445 }
2446
2447 CFRelease (families);
2448 val = Fnreverse (val);
2449 goto finish;
2450 err:
2451 val = Qnil;
2452
2453 finish:
2454 FONT_ADD_LOG ("macfont-list", spec, val);
2455 if (charset) CFRelease (charset);
2456 if (languages) CFRelease (languages);
2457 if (attributes) CFRelease (attributes);
2458 if (family_name) CFRelease (family_name);
2459
2460 unblock_input ();
2461
2462 return val;
2463 }
2464
2465 static Lisp_Object
2466 macfont_match (struct frame * frame, Lisp_Object spec)
2467 {
2468 Lisp_Object entity = Qnil;
2469 CFMutableDictionaryRef attributes;
2470 FontDescriptorRef pat_desc = NULL, desc = NULL;
2471
2472 block_input ();
2473
2474 attributes = macfont_create_attributes_with_spec (spec);
2475 if (attributes)
2476 {
2477 pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2478 CFRelease (attributes);
2479 }
2480 if (pat_desc)
2481 {
2482 desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2483 NULL);
2484 CFRelease (pat_desc);
2485 }
2486 if (desc)
2487 {
2488 entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2489 0);
2490 CFRelease (desc);
2491 }
2492 unblock_input ();
2493
2494 FONT_ADD_LOG ("macfont-match", spec, entity);
2495 return entity;
2496 }
2497
2498 static Lisp_Object
2499 macfont_list_family (struct frame *frame)
2500 {
2501 Lisp_Object list = Qnil;
2502 CFArrayRef families;
2503
2504 block_input ();
2505
2506 families = macfont_copy_available_families_cache ();
2507 if (families)
2508 {
2509 CFIndex i, count = CFArrayGetCount (families);
2510
2511 for (i = 0; i < count; i++)
2512 list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2513 CFRelease (families);
2514 }
2515
2516 unblock_input ();
2517
2518 return list;
2519 }
2520
2521 static void
2522 macfont_free_entity (Lisp_Object entity)
2523 {
2524 Lisp_Object val = assq_no_quit (QCfont_entity,
2525 AREF (entity, FONT_EXTRA_INDEX));
2526 CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2527
2528 block_input ();
2529 CFRelease (name);
2530 unblock_input ();
2531 }
2532
2533 static Lisp_Object
2534 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2535 {
2536 Lisp_Object val, font_object;
2537 CFStringRef font_name;
2538 struct macfont_info *macfont_info = NULL;
2539 struct font *font;
2540 int size;
2541 FontRef macfont;
2542 FontSymbolicTraits sym_traits;
2543 char name[256];
2544 int len, i, total_width;
2545 CGGlyph glyph;
2546 CGFloat ascent, descent, leading;
2547
2548 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2549 if (! CONSP (val)
2550 || XTYPE (XCDR (val)) != Lisp_Misc
2551 || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2552 return Qnil;
2553 font_name = XSAVE_POINTER (XCDR (val), 0);
2554 sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2555
2556 size = XINT (AREF (entity, FONT_SIZE_INDEX));
2557 if (size == 0)
2558 size = pixel_size;
2559
2560 block_input ();
2561 macfont = mac_font_create_with_name (font_name, size);
2562 if (macfont)
2563 {
2564 int fontsize = (int) [((NSFont *) macfont) pointSize];
2565 if (fontsize != size) size = fontsize;
2566 }
2567 unblock_input ();
2568 if (! macfont)
2569 return Qnil;
2570
2571 font_object = font_build_object (VECSIZE (struct macfont_info),
2572 Qmac_ct, entity, size);
2573 font = XFONT_OBJECT (font_object);
2574 font->pixel_size = size;
2575 font->driver = &macfont_driver;
2576 font->encoding_charset = font->repertory_charset = -1;
2577
2578 block_input ();
2579
2580 macfont_info = (struct macfont_info *) font;
2581 macfont_info->macfont = macfont;
2582 macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2583
2584 val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2585 if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2586 macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2587 size);
2588 else
2589 macfont_info->screen_font = NULL;
2590 macfont_info->cache = macfont_lookup_cache (font_name);
2591 macfont_retain_cache (macfont_info->cache);
2592 macfont_info->metrics = NULL;
2593 macfont_info->metrics_nrows = 0;
2594 macfont_info->synthetic_italic_p = 0;
2595 macfont_info->synthetic_bold_p = 0;
2596 macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2597 macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2598 if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2599 && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2600 macfont_info->synthetic_italic_p = 1;
2601 if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2602 && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2603 macfont_info->synthetic_bold_p = 1;
2604 if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2605 macfont_info->spacing = MACFONT_SPACING_MONO;
2606 else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2607 && (XINT (AREF (entity, FONT_SPACING_INDEX))
2608 == FONT_SPACING_SYNTHETIC_MONO))
2609 macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2610 if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2611 macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2612 else
2613 {
2614 val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2615 if (CONSP (val))
2616 macfont_info->antialias =
2617 NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2618 }
2619 macfont_info->color_bitmap_p = 0;
2620 if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2621 macfont_info->color_bitmap_p = 1;
2622
2623 glyph = macfont_get_glyph_for_character (font, ' ');
2624 if (glyph != kCGFontIndexInvalid)
2625 font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2626 else
2627 /* dirty workaround */
2628 font->space_width = pixel_size;
2629
2630 total_width = font->space_width;
2631 for (i = 1; i < 95; i++)
2632 {
2633 glyph = macfont_get_glyph_for_character (font, ' ' + i);
2634 if (glyph == kCGFontIndexInvalid)
2635 break;
2636 total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2637 }
2638 if (i == 95)
2639 font->average_width = total_width / 95;
2640 else
2641 font->average_width = font->space_width; /* XXX */
2642
2643 if (!(macfont_info->screen_font
2644 && mac_screen_font_get_metrics (macfont_info->screen_font,
2645 &ascent, &descent, &leading)))
2646 {
2647 CFStringRef family_name;
2648
2649 ascent = mac_font_get_ascent (macfont);
2650 descent = mac_font_get_descent (macfont);
2651 leading = mac_font_get_leading (macfont);
2652 /* AppKit and WebKit do some adjustment to the heights of
2653 Courier, Helvetica, and Times. */
2654 family_name = mac_font_copy_family_name (macfont);
2655 if (family_name)
2656 {
2657 if (CFEqual (family_name, CFSTR ("Courier"))
2658 || CFEqual (family_name, CFSTR ("Helvetica"))
2659 || CFEqual (family_name, CFSTR ("Times")))
2660 ascent += (ascent + descent) * .15f;
2661 else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2662 {
2663 leading *= .25f;
2664 ascent += leading;
2665 }
2666 CFRelease (family_name);
2667 }
2668 }
2669 font->ascent = ascent + 0.5f;
2670 val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2671 if (CONSP (val) && !NILP (XCDR (val)))
2672 font->descent = descent + 0.5f;
2673 else
2674 font->descent = descent + leading + 0.5f;
2675 font->height = font->ascent + font->descent;
2676
2677 font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2678 font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2679
2680 unblock_input ();
2681
2682 /* Unfortunately Xft doesn't provide a way to get minimum char
2683 width. So, we use space_width instead. */
2684 font->min_width = font->max_width = font->space_width; /* XXX */
2685
2686 font->baseline_offset = 0;
2687 font->relative_compose = 0;
2688 font->default_ascent = 0;
2689 font->vertical_centering = 0;
2690
2691 return font_object;
2692 }
2693
2694 static void
2695 macfont_close (struct font *font)
2696 {
2697 struct macfont_info *macfont_info = (struct macfont_info *) font;
2698
2699 if (macfont_info->cache)
2700 {
2701 int i;
2702
2703 block_input ();
2704 CFRelease (macfont_info->macfont);
2705 CGFontRelease (macfont_info->cgfont);
2706 if (macfont_info->screen_font)
2707 CFRelease (macfont_info->screen_font);
2708 macfont_release_cache (macfont_info->cache);
2709 for (i = 0; i < macfont_info->metrics_nrows; i++)
2710 if (macfont_info->metrics[i])
2711 xfree (macfont_info->metrics[i]);
2712 if (macfont_info->metrics)
2713 xfree (macfont_info->metrics);
2714 macfont_info->cache = NULL;
2715 unblock_input ();
2716 }
2717 }
2718
2719 static int
2720 macfont_has_char (Lisp_Object font, int c)
2721 {
2722 int result;
2723 CFCharacterSetRef charset;
2724
2725 block_input ();
2726 if (FONT_ENTITY_P (font))
2727 {
2728 Lisp_Object val;
2729 CFStringRef name;
2730
2731 val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2732 val = XCDR (val);
2733 name = XSAVE_POINTER (val, 0);
2734 charset = macfont_get_cf_charset_for_name (name);
2735 }
2736 else
2737 charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2738
2739 result = CFCharacterSetIsLongCharacterMember (charset, c);
2740 unblock_input ();
2741
2742 return result;
2743 }
2744
2745 static unsigned
2746 macfont_encode_char (struct font *font, int c)
2747 {
2748 struct macfont_info *macfont_info = (struct macfont_info *) font;
2749 CGGlyph glyph;
2750
2751 block_input ();
2752 glyph = macfont_get_glyph_for_character (font, c);
2753 unblock_input ();
2754
2755 return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2756 }
2757
2758 static void
2759 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2760 struct font_metrics *metrics)
2761 {
2762 int width, i;
2763
2764 block_input ();
2765 width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2766 for (i = 1; i < nglyphs; i++)
2767 {
2768 struct font_metrics m;
2769 int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2770 NULL, 0);
2771
2772 if (metrics)
2773 {
2774 if (width + m.lbearing < metrics->lbearing)
2775 metrics->lbearing = width + m.lbearing;
2776 if (width + m.rbearing > metrics->rbearing)
2777 metrics->rbearing = width + m.rbearing;
2778 if (m.ascent > metrics->ascent)
2779 metrics->ascent = m.ascent;
2780 if (m.descent > metrics->descent)
2781 metrics->descent = m.descent;
2782 }
2783 width += w;
2784 }
2785 unblock_input ();
2786
2787 if (metrics)
2788 metrics->width = width;
2789 }
2790
2791 static int
2792 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2793 bool with_background)
2794 {
2795 struct frame * f = s->f;
2796 struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2797 CGRect background_rect;
2798 CGPoint text_position;
2799 CGGlyph *glyphs;
2800 CGPoint *positions;
2801 CGFloat font_size = mac_font_get_size (macfont_info->macfont);
2802 bool no_antialias_p =
2803 (NILP (ns_antialias_text)
2804 || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2805 || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2806 && font_size <= macfont_antialias_threshold));
2807 int len = to - from;
2808 struct face *face = s->face;
2809 CGContextRef context;
2810
2811 block_input ();
2812
2813 if (with_background)
2814 background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2815 s->width, FONT_HEIGHT (s->font));
2816 else
2817 background_rect = CGRectNull;
2818
2819 text_position = CGPointMake (x, -y);
2820 glyphs = xmalloc (sizeof (CGGlyph) * len);
2821 {
2822 CGFloat advance_delta = 0;
2823 int i;
2824 CGFloat total_width = 0;
2825
2826 positions = xmalloc (sizeof (CGPoint) * len);
2827 for (i = 0; i < len; i++)
2828 {
2829 int width;
2830
2831 glyphs[i] = s->char2b[from + i];
2832 width = (s->padding_p ? 1
2833 : macfont_glyph_extents (s->font, glyphs[i],
2834 NULL, &advance_delta,
2835 no_antialias_p));
2836 positions[i].x = total_width + advance_delta;
2837 positions[i].y = 0;
2838 total_width += width;
2839 }
2840 }
2841
2842 context = [[NSGraphicsContext currentContext] graphicsPort];
2843 CGContextSaveGState (context);
2844
2845 if (!CGRectIsNull (background_rect))
2846 {
2847 if (s->hl == DRAW_MOUSE_FACE)
2848 {
2849 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2850 if (!face)
2851 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2852 }
2853 CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2854 CGContextFillRects (context, &background_rect, 1);
2855 }
2856
2857 if (macfont_info->cgfont)
2858 {
2859 CGAffineTransform atfm;
2860
2861 CGContextScaleCTM (context, 1, -1);
2862 CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2863 if (macfont_info->synthetic_italic_p)
2864 atfm = synthetic_italic_atfm;
2865 else
2866 atfm = CGAffineTransformIdentity;
2867 if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2868 {
2869 CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2870 CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2871 CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2872 }
2873 if (no_antialias_p)
2874 CGContextSetShouldAntialias (context, false);
2875
2876 CGContextSetTextMatrix (context, atfm);
2877 CGContextSetTextPosition (context, text_position.x, text_position.y);
2878
2879 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2880 if (macfont_info->color_bitmap_p
2881 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2882 && CTFontDrawGlyphs != NULL
2883 #endif
2884 )
2885 {
2886 if (len > 0)
2887 {
2888 CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2889 context);
2890 }
2891 }
2892 else
2893 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2894 {
2895 CGContextSetFont (context, macfont_info->cgfont);
2896 CGContextSetFontSize (context, font_size);
2897 CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2898 }
2899 }
2900
2901
2902 xfree (glyphs);
2903 xfree (positions);
2904 CGContextRestoreGState (context);
2905
2906 unblock_input ();
2907
2908 return len;
2909 }
2910
2911 static Lisp_Object
2912 macfont_shape (Lisp_Object lgstring)
2913 {
2914 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2915 struct macfont_info *macfont_info = (struct macfont_info *) font;
2916 FontRef macfont = macfont_info->macfont;
2917 ptrdiff_t glyph_len, len, i, j;
2918 CFIndex nonbmp_len;
2919 UniChar *unichars;
2920 CFIndex *nonbmp_indices;
2921 CFStringRef string;
2922 CFIndex used = 0;
2923 struct mac_glyph_layout *glyph_layouts;
2924
2925 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2926 nonbmp_len = 0;
2927 for (i = 0; i < glyph_len; i++)
2928 {
2929 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2930
2931 if (NILP (lglyph))
2932 break;
2933 if (LGLYPH_CHAR (lglyph) >= 0x10000)
2934 nonbmp_len++;
2935 }
2936
2937 len = i;
2938
2939 if (INT_MAX / 2 < len)
2940 memory_full (SIZE_MAX);
2941
2942 unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2943 nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2944 for (i = j = 0; i < len; i++)
2945 {
2946 UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2947
2948 if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2949 {
2950 nonbmp_indices[j] = i + j;
2951 j++;
2952 }
2953 }
2954 nonbmp_indices[j] = len + j; /* sentinel */
2955
2956 block_input ();
2957
2958 string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2959 kCFAllocatorNull);
2960 if (string)
2961 {
2962 glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2963 if (macfont_info->screen_font)
2964 used = mac_screen_font_shape (macfont_info->screen_font, string,
2965 glyph_layouts, glyph_len);
2966 else
2967 used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2968 CFRelease (string);
2969 }
2970
2971 unblock_input ();
2972
2973 if (used == 0)
2974 return Qnil;
2975
2976 block_input ();
2977
2978 for (i = 0; i < used; i++)
2979 {
2980 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2981 struct mac_glyph_layout *gl = glyph_layouts + i;
2982 EMACS_INT from, to;
2983 struct font_metrics metrics;
2984 int xoff, yoff, wadjust;
2985
2986 if (NILP (lglyph))
2987 {
2988 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2989 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2990 }
2991
2992 from = gl->comp_range.location;
2993 /* Convert UTF-16 index to UTF-32. */
2994 j = 0;
2995 while (nonbmp_indices[j] < from)
2996 j++;
2997 from -= j;
2998 LGLYPH_SET_FROM (lglyph, from);
2999
3000 to = gl->comp_range.location + gl->comp_range.length;
3001 /* Convert UTF-16 index to UTF-32. */
3002 while (nonbmp_indices[j] < to)
3003 j++;
3004 to -= j;
3005 LGLYPH_SET_TO (lglyph, to - 1);
3006
3007 /* LGLYPH_CHAR is used in `describe-char' for checking whether
3008 the composition is trivial. */
3009 {
3010 UTF32Char c;
3011
3012 if (unichars[gl->string_index] >= 0xD800
3013 && unichars[gl->string_index] < 0xDC00)
3014 c = (((unichars[gl->string_index] - 0xD800) << 10)
3015 + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3016 else
3017 c = unichars[gl->string_index];
3018 if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3019 c = 0;
3020 LGLYPH_SET_CHAR (lglyph, c);
3021 }
3022
3023 {
3024 unsigned long cc = gl->glyph_id;
3025 LGLYPH_SET_CODE (lglyph, cc);
3026 }
3027
3028 macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3029 LGLYPH_SET_WIDTH (lglyph, metrics.width);
3030 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3031 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3032 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3033 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3034
3035 xoff = lround (gl->advance_delta);
3036 yoff = lround (- gl->baseline_delta);
3037 wadjust = lround (gl->advance);
3038 if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3039 {
3040 Lisp_Object vec;
3041
3042 vec = Fmake_vector (make_number (3), Qnil);
3043 ASET (vec, 0, make_number (xoff));
3044 ASET (vec, 1, make_number (yoff));
3045 ASET (vec, 2, make_number (wadjust));
3046 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3047 }
3048 }
3049
3050 unblock_input ();
3051
3052 return make_number (used);
3053 }
3054
3055 /* Structures for the UVS subtable (format 14) in the cmap table. */
3056 typedef UInt8 UINT24[3];
3057
3058 #pragma pack(push, 1)
3059 struct variation_selector_record
3060 {
3061 UINT24 var_selector;
3062 UInt32 default_uvs_offset, non_default_uvs_offset;
3063 };
3064 struct uvs_table
3065 {
3066 UInt16 format;
3067 UInt32 length, num_var_selector_records;
3068 struct variation_selector_record variation_selector_records[1];
3069 };
3070 #define SIZEOF_UVS_TABLE_HEADER \
3071 (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3072
3073 struct unicode_value_range
3074 {
3075 UINT24 start_unicode_value;
3076 UInt8 additional_count;
3077 };
3078 struct default_uvs_table {
3079 UInt32 num_unicode_value_ranges;
3080 struct unicode_value_range unicode_value_ranges[1];
3081 };
3082 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3083 (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3084
3085 struct uvs_mapping
3086 {
3087 UINT24 unicode_value;
3088 UInt16 glyph_id;
3089 };
3090 struct non_default_uvs_table
3091 {
3092 UInt32 num_uvs_mappings;
3093 struct uvs_mapping uvs_mappings[1];
3094 };
3095 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3096 (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3097 #pragma pack(pop)
3098
3099 /* Read big endian values. The argument LVAL must be an lvalue. */
3100 /* I suppose OSReadBigInt* takes care of unaligned data. At least, we
3101 can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3102 OSReadBigInt16(cdb, 7);" in a sample code by Apple. */
3103 #define BUINT8_VALUE(lval) (*((UInt8 *) &(lval)))
3104 #define BUINT16_VALUE(lval) OSReadBigInt16 (&(lval), 0)
3105 /* Succeeding one byte should also be accessible. */
3106 #define BUINT24_VALUE(lval) (OSReadBigInt32 (&(lval), 0) >> 8)
3107 #define BUINT32_VALUE(lval) OSReadBigInt32 (&(lval), 0)
3108
3109 /* Return UVS subtable for the specified FONT. If the subtable is not
3110 found or ill-formatted, then return NULL. */
3111
3112 static CFDataRef
3113 mac_font_copy_uvs_table (FontRef font)
3114 {
3115 CFDataRef cmap_table, uvs_table = NULL;
3116
3117 cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3118 if (cmap_table)
3119 {
3120 sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3121 struct uvs_table *uvs;
3122 struct variation_selector_record *records;
3123 UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3124
3125 #if __LP64__
3126 if (CFDataGetLength (cmap_table) > UINT32_MAX)
3127 goto finish;
3128 #endif
3129
3130 cmap_len = CFDataGetLength (cmap_table);
3131 if (sizeof_sfntCMapHeader > cmap_len)
3132 goto finish;
3133
3134 ntables = BUINT16_VALUE (cmap->numTables);
3135 if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3136 / sizeof_sfntCMapEncoding))
3137 goto finish;
3138
3139 for (i = 0; i < ntables; i++)
3140 if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3141 == kFontUnicodePlatform)
3142 && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3143 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3144 {
3145 uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3146 break;
3147 }
3148 if (i == ntables
3149 || uvs_offset > cmap_len
3150 || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3151 goto finish;
3152
3153 uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3154 uvs_len = BUINT32_VALUE (uvs->length);
3155 if (uvs_len > cmap_len - uvs_offset
3156 || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3157 goto finish;
3158
3159 if (BUINT16_VALUE (uvs->format) != 14)
3160 goto finish;
3161
3162 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3163 if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3164 / sizeof (struct variation_selector_record)))
3165 goto finish;
3166
3167 records = uvs->variation_selector_records;
3168 for (i = 0; i < nrecords; i++)
3169 {
3170 UInt32 default_uvs_offset, non_default_uvs_offset;
3171
3172 default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3173 if (default_uvs_offset)
3174 {
3175 struct default_uvs_table *default_uvs;
3176 UInt32 nranges;
3177
3178 if (default_uvs_offset > uvs_len
3179 || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3180 > uvs_len - default_uvs_offset))
3181 goto finish;
3182
3183 default_uvs = ((struct default_uvs_table *)
3184 ((UInt8 *) uvs + default_uvs_offset));
3185 nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3186 if (nranges > ((uvs_len - default_uvs_offset
3187 - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3188 / sizeof (struct unicode_value_range)))
3189 goto finish;
3190 /* Now 2 * nranges can't overflow, so we can safely use
3191 `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3192 mac_font_get_glyphs_for_variants. */
3193 }
3194
3195 non_default_uvs_offset =
3196 BUINT32_VALUE (records[i].non_default_uvs_offset);
3197 if (non_default_uvs_offset)
3198 {
3199 struct non_default_uvs_table *non_default_uvs;
3200 UInt32 nmappings;
3201
3202 if (non_default_uvs_offset > uvs_len
3203 || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3204 > uvs_len - non_default_uvs_offset))
3205 goto finish;
3206
3207 non_default_uvs = ((struct non_default_uvs_table *)
3208 ((UInt8 *) uvs + non_default_uvs_offset));
3209 nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3210 if (nmappings > ((uvs_len - non_default_uvs_offset
3211 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3212 / sizeof (struct uvs_mapping)))
3213 goto finish;
3214 /* Now 2 * nmappings can't overflow, so we can safely
3215 use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3216 in mac_font_get_glyphs_for_variants. */
3217 }
3218 }
3219
3220 uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3221
3222 finish:
3223 CFRelease (cmap_table);
3224 }
3225
3226 return uvs_table;
3227 }
3228
3229 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3230 sequence consisting of the given base character C and each
3231 variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3232 result (explained below) into the corresponding GLYPHS[i]. If the
3233 entry is found in the Default UVS Table, then the result is 0. If
3234 the entry is found in the Non-Default UVS Table, then the result is
3235 the associated glyph ID. Otherwise, kCGFontIndexInvalid. The
3236 elements in SELECTORS must be sorted in strictly increasing
3237 order. */
3238
3239 static void
3240 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3241 const UTF32Char selectors[], CGGlyph glyphs[],
3242 CFIndex count)
3243 {
3244 struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3245 struct variation_selector_record *records = uvs->variation_selector_records;
3246 CFIndex i;
3247 UInt32 ir, nrecords;
3248 dispatch_queue_t queue =
3249 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3250 dispatch_group_t group = dispatch_group_create ();
3251
3252 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3253 i = 0;
3254 ir = 0;
3255 while (i < count && ir < nrecords)
3256 {
3257 UInt32 default_uvs_offset, non_default_uvs_offset;
3258
3259 if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3260 {
3261 glyphs[i++] = kCGFontIndexInvalid;
3262 continue;
3263 }
3264 else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3265 {
3266 ir++;
3267 continue;
3268 }
3269
3270 /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3271 default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3272 non_default_uvs_offset =
3273 BUINT32_VALUE (records[ir].non_default_uvs_offset);
3274 dispatch_group_async (group, queue, ^{
3275 glyphs[i] = kCGFontIndexInvalid;
3276
3277 if (default_uvs_offset)
3278 {
3279 struct default_uvs_table *default_uvs =
3280 (struct default_uvs_table *) ((UInt8 *) uvs
3281 + default_uvs_offset);
3282 struct unicode_value_range *ranges =
3283 default_uvs->unicode_value_ranges;
3284 UInt32 lo, hi;
3285
3286 lo = 0;
3287 hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3288 while (lo < hi)
3289 {
3290 UInt32 mid = (lo + hi) / 2;
3291
3292 if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3293 hi = mid;
3294 else
3295 lo = mid + 1;
3296 }
3297 if (hi > 0
3298 && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3299 + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3300 glyphs[i] = 0;
3301 }
3302
3303 if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3304 {
3305 struct non_default_uvs_table *non_default_uvs =
3306 (struct non_default_uvs_table *) ((UInt8 *) uvs
3307 + non_default_uvs_offset);
3308 struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3309 UInt32 lo, hi;
3310
3311 lo = 0;
3312 hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3313 while (lo < hi)
3314 {
3315 UInt32 mid = (lo + hi) / 2;
3316
3317 if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3318 hi = mid;
3319 else
3320 lo = mid + 1;
3321 }
3322 if (hi > 0 &&
3323 BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3324 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3325 }
3326 });
3327 i++;
3328 ir++;
3329 }
3330 while (i < count)
3331 glyphs[i++] = kCGFontIndexInvalid;
3332 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3333 dispatch_release (group);
3334 }
3335
3336 static int
3337 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3338 {
3339 CFDataRef uvs_table;
3340 CharacterCollection uvs_collection;
3341 int i, n = 0;
3342
3343 block_input ();
3344 uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3345
3346 if (uvs_table)
3347 {
3348 UTF32Char selectors[256];
3349 CGGlyph glyphs[256];
3350
3351 for (i = 0; i < 16; i++)
3352 selectors[i] = 0xFE00 + i;
3353 for (; i < 256; i++)
3354 selectors[i] = 0xE0100 + (i - 16);
3355 mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3356 for (i = 0; i < 256; i++)
3357 {
3358 CGGlyph glyph = glyphs[i];
3359
3360 if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3361 && glyph != kCGFontIndexInvalid)
3362 glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3363 if (glyph == kCGFontIndexInvalid)
3364 variations[i] = 0;
3365 else
3366 {
3367 variations[i] = (glyph ? glyph
3368 : macfont_get_glyph_for_character (font, c));
3369 n++;
3370 }
3371 }
3372 }
3373 unblock_input ();
3374
3375 return n;
3376 }
3377
3378 static const char *const macfont_booleans[] = {
3379 ":antialias",
3380 ":minspace",
3381 NULL,
3382 };
3383
3384 static const char *const macfont_non_booleans[] = {
3385 ":lang",
3386 ":script",
3387 ":destination",
3388 NULL,
3389 };
3390
3391 static void
3392 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3393 {
3394 font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3395 }
3396
3397 static Boolean
3398 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3399 CFArrayRef languages)
3400 {
3401 Boolean result = true;
3402 CFArrayRef desc_languages =
3403 CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3404
3405 if (desc_languages == NULL)
3406 result = false;
3407 else
3408 {
3409 CFIndex desc_languages_count, i, languages_count;
3410
3411 desc_languages_count = CFArrayGetCount (desc_languages);
3412 languages_count = CFArrayGetCount (languages);
3413 for (i = 0; i < languages_count; i++)
3414 if (!CFArrayContainsValue (desc_languages,
3415 CFRangeMake (0, desc_languages_count),
3416 CFArrayGetValueAtIndex (languages, i)))
3417 {
3418 result = false;
3419 break;
3420 }
3421 CFRelease (desc_languages);
3422 }
3423
3424 return result;
3425 }
3426
3427 static CFStringRef
3428 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3429 {
3430 CFStringRef result = NULL;
3431 CFStringRef charset_string =
3432 CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3433
3434 if (charset_string && CFStringGetLength (charset_string) > 0)
3435 {
3436 CFStringRef keys[] = {
3437 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3438 kCTLanguageAttributeName
3439 #else
3440 CFSTR ("NSLanguage")
3441 #endif
3442 };
3443 CFTypeRef values[] = {NULL};
3444 CFIndex num_values = 0;
3445 CFArrayRef languages
3446 = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3447
3448 if (languages && CFArrayGetCount (languages) > 0)
3449 {
3450 if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3451 values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3452 else
3453 {
3454 CFCharacterSetRef charset =
3455 CFDictionaryGetValue (attributes,
3456 MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3457
3458 result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3459 }
3460 }
3461 if (result == NULL)
3462 {
3463 CFAttributedStringRef attr_string = NULL;
3464 CTLineRef ctline = NULL;
3465 CFDictionaryRef attrs
3466 = CFDictionaryCreate (NULL, (const void **) keys,
3467 (const void **) values, num_values,
3468 &kCFTypeDictionaryKeyCallBacks,
3469 &kCFTypeDictionaryValueCallBacks);
3470
3471 if (attrs)
3472 {
3473 attr_string = CFAttributedStringCreate (NULL, charset_string,
3474 attrs);
3475 CFRelease (attrs);
3476 }
3477 if (attr_string)
3478 {
3479 ctline = CTLineCreateWithAttributedString (attr_string);
3480 CFRelease (attr_string);
3481 }
3482 if (ctline)
3483 {
3484 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3485 CFIndex i, nruns = CFArrayGetCount (runs);
3486 CTFontRef font;
3487
3488 for (i = 0; i < nruns; i++)
3489 {
3490 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3491 CFDictionaryRef attributes = CTRunGetAttributes (run);
3492 CTFontRef font_in_run;
3493
3494 if (attributes == NULL)
3495 break;
3496 font_in_run =
3497 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3498 if (font_in_run == NULL)
3499 break;
3500 if (i == 0)
3501 font = font_in_run;
3502 else if (!mac_ctfont_equal_in_postscript_name (font,
3503 font_in_run))
3504 break;
3505 }
3506 if (nruns > 0 && i == nruns)
3507 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3508 CFRelease (ctline);
3509 }
3510 }
3511 }
3512
3513 return result;
3514 }
3515
3516 static inline double
3517 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3518 {
3519 return CTFontGetAdvancesForGlyphs (font,
3520 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3521 kCTFontOrientationDefault,
3522 #else
3523 kCTFontDefaultOrientation,
3524 #endif
3525 &glyph, NULL, 1);
3526 }
3527
3528 static inline CGRect
3529 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3530 {
3531 return CTFontGetBoundingRectsForGlyphs (font,
3532 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3533 kCTFontOrientationDefault,
3534 #else
3535 kCTFontDefaultOrientation,
3536 #endif
3537 &glyph, NULL, 1);
3538 }
3539
3540 static CFArrayRef
3541 mac_ctfont_create_available_families (void)
3542 {
3543 CFMutableArrayRef families = NULL;
3544
3545 {
3546 CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3547
3548 if (orig_families)
3549 {
3550 CFIndex i, count = CFArrayGetCount (orig_families);
3551
3552 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3553 if (families)
3554 for (i = 0; i < count; i++)
3555 {
3556 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3557
3558 if (!CFStringHasPrefix (family, CFSTR ("."))
3559 && (CTFontManagerCompareFontFamilyNames (family,
3560 CFSTR ("LastResort"),
3561 NULL)
3562 != kCFCompareEqualTo))
3563 CFArrayAppendValue (families, family);
3564 }
3565 CFRelease (orig_families);
3566 }
3567 }
3568
3569 return families;
3570 }
3571
3572 static Boolean
3573 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3574 {
3575 Boolean result;
3576 CFStringRef name1, name2;
3577
3578 if (font1 == font2)
3579 return true;
3580
3581 result = false;
3582 name1 = CTFontCopyPostScriptName (font1);
3583 if (name1)
3584 {
3585 name2 = CTFontCopyPostScriptName (font2);
3586 if (name2)
3587 {
3588 result = CFEqual (name1, name2);
3589 CFRelease (name2);
3590 }
3591 CFRelease (name1);
3592 }
3593
3594 return result;
3595 }
3596
3597 static CTLineRef
3598 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3599 CTFontRef macfont)
3600 {
3601 CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3602 CFTypeRef values[] = {NULL, NULL};
3603 CFDictionaryRef attributes = NULL;
3604 CFAttributedStringRef attr_string = NULL;
3605 CTLineRef ctline = NULL;
3606 float float_zero = 0.0f;
3607
3608 values[0] = macfont;
3609 values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3610 if (values[1])
3611 {
3612 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3613 (const void **) values,
3614 ARRAYELTS (keys),
3615 &kCFTypeDictionaryKeyCallBacks,
3616 &kCFTypeDictionaryValueCallBacks);
3617 CFRelease (values[1]);
3618 }
3619 if (attributes)
3620 {
3621 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3622 CFRelease (attributes);
3623 }
3624 if (attr_string)
3625 {
3626 ctline = CTLineCreateWithAttributedString (attr_string);
3627 CFRelease (attr_string);
3628 }
3629 if (ctline)
3630 {
3631 /* Abandon if ctline contains some fonts other than the
3632 specified one. */
3633 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3634 CFIndex i, nruns = CFArrayGetCount (runs);
3635
3636 for (i = 0; i < nruns; i++)
3637 {
3638 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3639 CFDictionaryRef attributes = CTRunGetAttributes (run);
3640 CTFontRef font_in_run;
3641
3642 if (attributes == NULL)
3643 break;
3644 font_in_run =
3645 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3646 if (font_in_run == NULL)
3647 break;
3648 if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3649 break;
3650 }
3651 if (i < nruns)
3652 {
3653 CFRelease (ctline);
3654 ctline = NULL;
3655 }
3656 }
3657
3658 return ctline;
3659 }
3660
3661 static CFIndex
3662 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3663 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3664 {
3665 CFIndex used, result = 0;
3666 CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3667
3668 if (ctline == NULL)
3669 return 0;
3670
3671 used = CTLineGetGlyphCount (ctline);
3672 if (used <= glyph_len)
3673 {
3674 CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3675 CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3676 CGFloat total_advance = 0;
3677 CFIndex total_glyph_count = 0;
3678
3679 for (k = 0; k < ctrun_count; k++)
3680 {
3681 CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3682 CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3683 struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3684 CFRange string_range, comp_range, range;
3685 CFIndex *permutation;
3686
3687 if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3688 permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3689 else
3690 permutation = NULL;
3691
3692 #define RIGHT_TO_LEFT_P permutation
3693
3694 /* Now the `comp_range' member of struct mac_glyph_layout is
3695 temporarily used as a work area such that:
3696 glbuf[i].comp_range.location =
3697 min {compRange[i + 1].location, ...,
3698 compRange[glyph_count - 1].location,
3699 maxRange (stringRangeForCTRun)}
3700 glbuf[i].comp_range.length = maxRange (compRange[i])
3701 where compRange[i] is the range of composed characters
3702 containing i-th glyph. */
3703 string_range = CTRunGetStringRange (ctrun);
3704 min_location = string_range.location + string_range.length;
3705 for (i = 0; i < glyph_count; i++)
3706 {
3707 struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3708 CFIndex glyph_index;
3709 CFRange rng;
3710
3711 if (!RIGHT_TO_LEFT_P)
3712 glyph_index = glyph_count - i - 1;
3713 else
3714 glyph_index = i;
3715 CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3716 &gl->string_index);
3717 rng =
3718 CFStringGetRangeOfComposedCharactersAtIndex (string,
3719 gl->string_index);
3720 gl->comp_range.location = min_location;
3721 gl->comp_range.length = rng.location + rng.length;
3722 if (rng.location < min_location)
3723 min_location = rng.location;
3724 }
3725
3726 /* Fill the `comp_range' member of struct mac_glyph_layout,
3727 and setup a permutation for right-to-left text. */
3728 comp_range = CFRangeMake (string_range.location, 0);
3729 range = CFRangeMake (0, 0);
3730 while (1)
3731 {
3732 struct mac_glyph_layout *gl =
3733 glbuf + range.location + range.length;
3734
3735 if (gl->comp_range.length
3736 > comp_range.location + comp_range.length)
3737 comp_range.length = gl->comp_range.length - comp_range.location;
3738 min_location = gl->comp_range.location;
3739 range.length++;
3740
3741 if (min_location >= comp_range.location + comp_range.length)
3742 {
3743 comp_range.length = min_location - comp_range.location;
3744 for (i = 0; i < range.length; i++)
3745 {
3746 glbuf[range.location + i].comp_range = comp_range;
3747 if (RIGHT_TO_LEFT_P)
3748 permutation[range.location + i] =
3749 range.location + range.length - i - 1;
3750 }
3751
3752 comp_range = CFRangeMake (min_location, 0);
3753 range.location += range.length;
3754 range.length = 0;
3755 if (range.location == glyph_count)
3756 break;
3757 }
3758 }
3759
3760 /* Then fill the remaining members. */
3761 for (range = CFRangeMake (0, 1); range.location < glyph_count;
3762 range.location++)
3763 {
3764 struct mac_glyph_layout *gl;
3765 CGPoint position;
3766
3767 if (!RIGHT_TO_LEFT_P)
3768 gl = glbuf + range.location;
3769 else
3770 {
3771 CFIndex src, dest;
3772
3773 src = glyph_count - 1 - range.location;
3774 dest = permutation[src];
3775 gl = glbuf + dest;
3776 if (src < dest)
3777 {
3778 CFIndex tmp = gl->string_index;
3779
3780 gl->string_index = glbuf[src].string_index;
3781 glbuf[src].string_index = tmp;
3782 }
3783 }
3784 CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3785
3786 CTRunGetPositions (ctrun, range, &position);
3787 gl->advance_delta = position.x - total_advance;
3788 gl->baseline_delta = position.y;
3789 gl->advance = (gl->advance_delta
3790 + CTRunGetTypographicBounds (ctrun, range,
3791 NULL, NULL, NULL));
3792 total_advance += gl->advance;
3793 }
3794
3795 if (RIGHT_TO_LEFT_P)
3796 xfree (permutation);
3797
3798 #undef RIGHT_TO_LEFT_P
3799
3800 total_glyph_count += glyph_count;
3801 }
3802
3803 result = used;
3804 }
3805 CFRelease (ctline);
3806
3807 return result;
3808 }
3809
3810 /* The function below seems to cause a memory leak for the CFString
3811 created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3812 10.6.3. For now, we use the NSGlyphInfo version instead. */
3813 #if USE_CT_GLYPH_INFO
3814 static CGGlyph
3815 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3816 CGFontIndex cid)
3817 {
3818 CGGlyph result = kCGFontIndexInvalid;
3819 UniChar characters[] = {0xfffd};
3820 CFStringRef string;
3821 CFAttributedStringRef attr_string = NULL;
3822 CTLineRef ctline = NULL;
3823
3824 string = CFStringCreateWithCharacters (NULL, characters,
3825 ARRAYELTS (characters));
3826
3827 if (string)
3828 {
3829 CTGlyphInfoRef glyph_info =
3830 CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3831 CFDictionaryRef attributes = NULL;
3832
3833 if (glyph_info)
3834 {
3835 CFStringRef keys[] = {kCTFontAttributeName,
3836 kCTGlyphInfoAttributeName};
3837 CFTypeRef values[] = {font, glyph_info};
3838
3839 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3840 (const void **) values,
3841 ARRAYELTS (keys),
3842 &kCFTypeDictionaryKeyCallBacks,
3843 &kCFTypeDictionaryValueCallBacks);
3844 CFRelease (glyph_info);
3845 }
3846 if (attributes)
3847 {
3848 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3849 CFRelease (attributes);
3850 }
3851 CFRelease (string);
3852 }
3853 if (attr_string)
3854 {
3855 ctline = CTLineCreateWithAttributedString (attr_string);
3856 CFRelease (attr_string);
3857 }
3858 if (ctline)
3859 {
3860 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3861
3862 if (CFArrayGetCount (runs) > 0)
3863 {
3864 CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3865 CFDictionaryRef attributes = CTRunGetAttributes (run);
3866
3867 if (attributes)
3868 {
3869 CTFontRef font_in_run =
3870 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3871
3872 if (font_in_run
3873 && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3874 {
3875 CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3876 if (result >= CTFontGetGlyphCount (font))
3877 result = kCGFontIndexInvalid;
3878 }
3879 }
3880 }
3881 CFRelease (ctline);
3882 }
3883
3884 return result;
3885 }
3886 #endif
3887
3888 static CFArrayRef
3889 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3890 {
3891 CFArrayRef result = NULL;
3892
3893 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3894 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3895 if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3896 #endif
3897 {
3898 CTFontRef user_font =
3899 CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3900
3901 if (user_font)
3902 {
3903 CFArrayRef languages =
3904 CFArrayCreate (NULL, (const void **) &language, 1,
3905 &kCFTypeArrayCallBacks);
3906
3907 if (languages)
3908 {
3909 result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3910 languages);
3911 CFRelease (languages);
3912 }
3913 CFRelease (user_font);
3914 }
3915 }
3916 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3917 else /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3918 #endif
3919 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3920 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3921 {
3922 CFIndex i;
3923
3924 for (i = 0; macfont_language_default_font_names[i].language; i++)
3925 {
3926 if (CFEqual (macfont_language_default_font_names[i].language,
3927 language))
3928 {
3929 CFMutableArrayRef descriptors =
3930 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3931
3932 if (descriptors)
3933 {
3934 CFIndex j;
3935
3936 for (j = 0;
3937 macfont_language_default_font_names[i].font_names[j];
3938 j++)
3939 {
3940 CFDictionaryRef attributes =
3941 CFDictionaryCreate (NULL,
3942 ((const void **)
3943 &MAC_FONT_NAME_ATTRIBUTE),
3944 ((const void **)
3945 &macfont_language_default_font_names[i].font_names[j]),
3946 1, &kCFTypeDictionaryKeyCallBacks,
3947 &kCFTypeDictionaryValueCallBacks);
3948
3949 if (attributes)
3950 {
3951 FontDescriptorRef pat_desc =
3952 mac_font_descriptor_create_with_attributes (attributes);
3953
3954 if (pat_desc)
3955 {
3956 FontDescriptorRef descriptor =
3957 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3958
3959 if (descriptor)
3960 {
3961 CFArrayAppendValue (descriptors, descriptor);
3962 CFRelease (descriptor);
3963 }
3964 CFRelease (pat_desc);
3965 }
3966 CFRelease (attributes);
3967 }
3968 }
3969 result = descriptors;
3970 }
3971 break;
3972 }
3973 }
3974 }
3975 #endif
3976
3977 return result;
3978 }
3979
3980 static CFStringRef
3981 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3982 CFArrayRef languages)
3983 {
3984 CFStringRef result = NULL;
3985 CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3986 CFArrayRef descriptors =
3987 mac_font_copy_default_descriptors_for_language (language);
3988
3989 if (descriptors)
3990 {
3991 CFIndex i, count = CFArrayGetCount (descriptors);
3992
3993 for (i = 0; i < count; i++)
3994 {
3995 FontDescriptorRef descriptor =
3996 CFArrayGetValueAtIndex (descriptors, i);
3997
3998 if (macfont_supports_charset_and_languages_p (descriptor, charset,
3999 Qnil, languages))
4000 {
4001 CFStringRef family =
4002 mac_font_descriptor_copy_attribute (descriptor,
4003 MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4004 if (family)
4005 {
4006 if (!CFStringHasPrefix (family, CFSTR ("."))
4007 && !CFEqual (family, CFSTR ("LastResort")))
4008 {
4009 result = family;
4010 break;
4011 }
4012 else
4013 CFRelease (family);
4014 }
4015 }
4016 }
4017 CFRelease (descriptors);
4018 }
4019
4020 return result;
4021 }
4022
4023 void *
4024 macfont_get_nsctfont (struct font *font)
4025 {
4026 struct macfont_info *macfont_info = (struct macfont_info *) font;
4027 FontRef macfont = macfont_info->macfont;
4028
4029 return (void *) macfont;
4030 }
4031
4032 void
4033 mac_register_font_driver (struct frame *f)
4034 {
4035 register_font_driver (&macfont_driver, f);
4036 }
4037
4038 \f
4039 void
4040 syms_of_macfont (void)
4041 {
4042 static struct font_driver mac_font_driver;
4043
4044 /* Core Text, for Mac OS X. */
4045 DEFSYM (Qmac_ct, "mac-ct");
4046 macfont_driver.type = Qmac_ct;
4047 register_font_driver (&macfont_driver, NULL);
4048
4049 /* The font property key specifying the font design destination. The
4050 value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4051 text. (See the documentation of X Logical Font Description
4052 Conventions.) In the Mac font driver, 1 means the screen font is
4053 used for calculating some glyph metrics. You can see the
4054 difference with Monaco 8pt or 9pt, for example. */
4055 DEFSYM (QCdestination, ":destination");
4056
4057 /* The boolean-valued font property key specifying the use of leading. */
4058 DEFSYM (QCminspace, ":minspace");
4059
4060 macfont_family_cache = Qnil;
4061 staticpro (&macfont_family_cache);
4062 }