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