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