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