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