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