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