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