Add set operations for bool-vector.
[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 frame *, 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 frame * f, struct font *font)
2584 {
2585 struct macfont_info *macfont_info = (struct macfont_info *) font;
2586 int i;
2587
2588 block_input ();
2589 CFRelease (macfont_info->macfont);
2590 CGFontRelease (macfont_info->cgfont);
2591 if (macfont_info->screen_font)
2592 CFRelease (macfont_info->screen_font);
2593 macfont_release_cache (macfont_info->cache);
2594 for (i = 0; i < macfont_info->metrics_nrows; i++)
2595 if (macfont_info->metrics[i])
2596 xfree (macfont_info->metrics[i]);
2597 if (macfont_info->metrics)
2598 xfree (macfont_info->metrics);
2599 unblock_input ();
2600 }
2601
2602 static int
2603 macfont_has_char (Lisp_Object font, int c)
2604 {
2605 int result;
2606 CFCharacterSetRef charset;
2607
2608 block_input ();
2609 if (FONT_ENTITY_P (font))
2610 {
2611 Lisp_Object val;
2612 CFStringRef name;
2613
2614 val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2615 val = XCDR (val);
2616 name = XSAVE_POINTER (val, 0);
2617 charset = macfont_get_cf_charset_for_name (name);
2618 }
2619 else
2620 charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2621
2622 result = CFCharacterSetIsLongCharacterMember (charset, c);
2623 unblock_input ();
2624
2625 return result;
2626 }
2627
2628 static unsigned
2629 macfont_encode_char (struct font *font, int c)
2630 {
2631 struct macfont_info *macfont_info = (struct macfont_info *) font;
2632 CGGlyph glyph;
2633
2634 block_input ();
2635 glyph = macfont_get_glyph_for_character (font, c);
2636 unblock_input ();
2637
2638 return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2639 }
2640
2641 static int
2642 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2643 struct font_metrics *metrics)
2644 {
2645 int width, i;
2646
2647 block_input ();
2648 width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2649 for (i = 1; i < nglyphs; i++)
2650 {
2651 struct font_metrics m;
2652 int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2653 NULL, 0);
2654
2655 if (metrics)
2656 {
2657 if (width + m.lbearing < metrics->lbearing)
2658 metrics->lbearing = width + m.lbearing;
2659 if (width + m.rbearing > metrics->rbearing)
2660 metrics->rbearing = width + m.rbearing;
2661 if (m.ascent > metrics->ascent)
2662 metrics->ascent = m.ascent;
2663 if (m.descent > metrics->descent)
2664 metrics->descent = m.descent;
2665 }
2666 width += w;
2667 }
2668 unblock_input ();
2669
2670 if (metrics)
2671 metrics->width = width;
2672
2673 return width;
2674 }
2675
2676 static int
2677 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2678 bool with_background)
2679 {
2680 struct frame * f = s->f;
2681 struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2682 FontRef macfont = macfont_info->macfont;
2683 CGContextRef context;
2684 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2685 int end = isComposite ? s->cmp_to : s->nchars;
2686 int len = end - s->cmp_from;
2687 int i;
2688
2689 block_input ();
2690
2691 context = [[NSGraphicsContext currentContext] graphicsPort];
2692 CGContextSaveGState (context);
2693
2694 #if 0
2695 if (s->num_clips > 0)
2696 {
2697 CGRect clips[2];
2698
2699 for (i = 0; i < s->num_clips; i++)
2700 clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2701 s->clip[i].right - s->clip[i].left,
2702 s->clip[i].bottom - s->clip[i].top);
2703 CGContextClipToRects (context, clips, s->num_clips);
2704 }
2705 #endif
2706
2707 if (with_background)
2708 {
2709 CG_SET_FILL_COLOR_WITH_GC_BACKGROUND (context, s);
2710 CGContextFillRect (context,
2711 NSMakeRect (x, y,
2712 s->width, FONT_HEIGHT (s->font)));
2713 }
2714
2715 if (macfont_info->cgfont)
2716 {
2717 CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2718 CGPoint *positions = alloca (sizeof (CGPoint) * len);
2719 CGFloat total_width = 0;
2720 CGFloat font_size = mac_font_get_size (macfont);
2721 CGAffineTransform atfm;
2722 CGFloat advance_delta = 0;
2723 int y_draw = -y-FONT_BASE (s->font);
2724 int no_antialias_p =
2725 (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2726 || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2727 && font_size <= macfont_antialias_threshold));
2728
2729 for (i = 0; i < len; i++)
2730 {
2731 int width;
2732
2733 glyphs[i] = *(s->char2b + s->cmp_from + i);
2734 width = (s->padding_p ? 1
2735 : macfont_glyph_extents (s->font, glyphs[i],
2736 NULL, &advance_delta,
2737 no_antialias_p));
2738 positions[i].x = total_width + advance_delta;
2739 positions[i].y = 0;
2740 total_width += width;
2741 }
2742
2743 CGContextScaleCTM (context, 1, -1);
2744 CG_SET_FILL_COLOR_WITH_GC_FOREGROUND (context, s);
2745 if (macfont_info->synthetic_italic_p)
2746 atfm = synthetic_italic_atfm;
2747 else
2748 atfm = CGAffineTransformIdentity;
2749 if (macfont_info->synthetic_bold_p)
2750 {
2751 CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2752 CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2753 CG_SET_STROKE_COLOR_WITH_GC_FOREGROUND (context, s);
2754 }
2755 if (no_antialias_p)
2756 CGContextSetShouldAntialias (context, false);
2757
2758 CGContextSetTextMatrix (context, atfm);
2759 CGContextSetTextPosition (context, x, y_draw);
2760
2761 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2762 if (macfont_info->color_bitmap_p
2763 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2764 && CTFontDrawGlyphs != NULL
2765 #endif
2766 )
2767 {
2768 if (len > 0)
2769 {
2770 CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2771 }
2772 }
2773 else
2774 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2775 {
2776 CGContextSetFont (context, macfont_info->cgfont);
2777 CGContextSetFontSize (context, font_size);
2778 CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2779 }
2780 }
2781
2782 CGContextRestoreGState (context);
2783
2784 unblock_input ();
2785
2786 return len;
2787 }
2788
2789 Lisp_Object
2790 macfont_shape (Lisp_Object lgstring)
2791 {
2792 struct font *font;
2793 struct macfont_info *macfont_info;
2794 FontRef macfont;
2795 ptrdiff_t glyph_len, len, i, j;
2796 CFIndex nonbmp_len;
2797 UniChar *unichars;
2798 CFIndex *nonbmp_indices;
2799 CFStringRef string;
2800 CFIndex used = 0;
2801 struct mac_glyph_layout *glyph_layouts;
2802
2803 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2804 macfont_info = (struct macfont_info *) font;
2805 macfont = macfont_info->macfont;
2806
2807 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2808 nonbmp_len = 0;
2809 for (i = 0; i < glyph_len; i++)
2810 {
2811 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2812
2813 if (NILP (lglyph))
2814 break;
2815 if (LGLYPH_CHAR (lglyph) >= 0x10000)
2816 nonbmp_len++;
2817 }
2818
2819 len = i;
2820 assume (len <= TYPE_MAXIMUM (EMACS_INT) - 2);
2821
2822 if (INT_MAX / 2 < len)
2823 memory_full (SIZE_MAX);
2824
2825 unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2826 nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2827 for (i = j = 0; i < len; i++)
2828 {
2829 UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2830
2831 if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2832 {
2833 nonbmp_indices[j] = i + j;
2834 j++;
2835 }
2836 }
2837 nonbmp_indices[j] = len + j; /* sentinel */
2838
2839 block_input ();
2840
2841 string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2842 kCFAllocatorNull);
2843 if (string)
2844 {
2845 glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2846 if (macfont_info->screen_font)
2847 used = mac_screen_font_shape (macfont_info->screen_font, string,
2848 glyph_layouts, glyph_len);
2849 else
2850 used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2851 CFRelease (string);
2852 }
2853
2854 unblock_input ();
2855
2856 if (used == 0)
2857 return Qnil;
2858
2859 block_input ();
2860
2861 for (i = 0; i < used; i++)
2862 {
2863 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2864 struct mac_glyph_layout *gl = glyph_layouts + i;
2865 EMACS_INT from, to;
2866 struct font_metrics metrics;
2867 int xoff, yoff, wadjust;
2868
2869 if (NILP (lglyph))
2870 {
2871 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2872 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2873 }
2874
2875 from = gl->comp_range.location;
2876 /* Convert UTF-16 index to UTF-32. */
2877 j = 0;
2878 while (nonbmp_indices[j] < from)
2879 j++;
2880 from -= j;
2881 LGLYPH_SET_FROM (lglyph, from);
2882
2883 to = gl->comp_range.location + gl->comp_range.length;
2884 /* Convert UTF-16 index to UTF-32. */
2885 while (nonbmp_indices[j] < to)
2886 j++;
2887 to -= j;
2888 LGLYPH_SET_TO (lglyph, to - 1);
2889
2890 /* LGLYPH_CHAR is used in `describe-char' for checking whether
2891 the composition is trivial. */
2892 {
2893 UTF32Char c;
2894
2895 if (unichars[gl->string_index] >= 0xD800
2896 && unichars[gl->string_index] < 0xDC00)
2897 c = (((unichars[gl->string_index] - 0xD800) << 10)
2898 + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2899 else
2900 c = unichars[gl->string_index];
2901 if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2902 c = 0;
2903 LGLYPH_SET_CHAR (lglyph, c);
2904 }
2905
2906 {
2907 unsigned long cc = gl->glyph_id;
2908 LGLYPH_SET_CODE (lglyph, cc);
2909 }
2910
2911 macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2912 LGLYPH_SET_WIDTH (lglyph, metrics.width);
2913 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2914 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2915 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2916 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2917
2918 xoff = lround (gl->advance_delta);
2919 yoff = lround (- gl->baseline_delta);
2920 wadjust = lround (gl->advance);
2921 if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2922 {
2923 Lisp_Object vec;
2924
2925 vec = Fmake_vector (make_number (3), Qnil);
2926 ASET (vec, 0, make_number (xoff));
2927 ASET (vec, 1, make_number (yoff));
2928 ASET (vec, 2, make_number (wadjust));
2929 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2930 }
2931 }
2932
2933 unblock_input ();
2934
2935 return make_number (used);
2936 }
2937
2938 /* Structures for the UVS subtable (format 14) in the cmap table. */
2939 typedef UInt8 UINT24[3];
2940
2941 #pragma pack(push, 1)
2942 struct variation_selector_record
2943 {
2944 UINT24 var_selector;
2945 UInt32 default_uvs_offset, non_default_uvs_offset;
2946 };
2947 struct uvs_table
2948 {
2949 UInt16 format;
2950 UInt32 length, num_var_selector_records;
2951 struct variation_selector_record variation_selector_records[1];
2952 };
2953 #define SIZEOF_UVS_TABLE_HEADER \
2954 (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2955
2956 struct unicode_value_range
2957 {
2958 UINT24 start_unicode_value;
2959 UInt8 additional_count;
2960 };
2961 struct default_uvs_table {
2962 UInt32 num_unicode_value_ranges;
2963 struct unicode_value_range unicode_value_ranges[1];
2964 };
2965 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
2966 (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2967
2968 struct uvs_mapping
2969 {
2970 UINT24 unicode_value;
2971 UInt16 glyph_id;
2972 };
2973 struct non_default_uvs_table
2974 {
2975 UInt32 num_uvs_mappings;
2976 struct uvs_mapping uvs_mappings[1];
2977 };
2978 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
2979 (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
2980 #pragma pack(pop)
2981
2982 /* Read big endian values. The argument LVAL must be an lvalue. */
2983 /* I suppose OSReadBigInt* takes care of unaligned data. At least, we
2984 can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
2985 OSReadBigInt16(cdb, 7);" in a sample code by Apple. */
2986 #define BUINT8_VALUE(lval) (*((UInt8 *) &(lval)))
2987 #define BUINT16_VALUE(lval) OSReadBigInt16 (&(lval), 0)
2988 /* Succeeding one byte should also be accessible. */
2989 #define BUINT24_VALUE(lval) (OSReadBigInt32 (&(lval), 0) >> 8)
2990 #define BUINT32_VALUE(lval) OSReadBigInt32 (&(lval), 0)
2991
2992 /* Return UVS subtable for the specified FONT. If the subtable is not
2993 found or ill-formated, then return NULL. */
2994
2995 static CFDataRef
2996 mac_font_copy_uvs_table (FontRef font)
2997 {
2998 CFDataRef cmap_table, uvs_table = NULL;
2999
3000 cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3001 if (cmap_table)
3002 {
3003 sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3004 struct uvs_table *uvs;
3005 struct variation_selector_record *records;
3006 UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3007
3008 #if __LP64__
3009 if (CFDataGetLength (cmap_table) > UINT32_MAX)
3010 goto finish;
3011 #endif
3012
3013 cmap_len = CFDataGetLength (cmap_table);
3014 if (sizeof_sfntCMapHeader > cmap_len)
3015 goto finish;
3016
3017 ntables = BUINT16_VALUE (cmap->numTables);
3018 if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3019 / sizeof_sfntCMapEncoding))
3020 goto finish;
3021
3022 for (i = 0; i < ntables; i++)
3023 if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3024 == kFontUnicodePlatform)
3025 && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3026 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3027 {
3028 uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3029 break;
3030 }
3031 if (i == ntables
3032 || uvs_offset > cmap_len
3033 || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3034 goto finish;
3035
3036 uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3037 uvs_len = BUINT32_VALUE (uvs->length);
3038 if (uvs_len > cmap_len - uvs_offset
3039 || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3040 goto finish;
3041
3042 if (BUINT16_VALUE (uvs->format) != 14)
3043 goto finish;
3044
3045 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3046 if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3047 / sizeof (struct variation_selector_record)))
3048 goto finish;
3049
3050 records = uvs->variation_selector_records;
3051 for (i = 0; i < nrecords; i++)
3052 {
3053 UInt32 default_uvs_offset, non_default_uvs_offset;
3054
3055 default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3056 if (default_uvs_offset)
3057 {
3058 struct default_uvs_table *default_uvs;
3059 UInt32 nranges;
3060
3061 if (default_uvs_offset > uvs_len
3062 || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3063 > uvs_len - default_uvs_offset))
3064 goto finish;
3065
3066 default_uvs = ((struct default_uvs_table *)
3067 ((UInt8 *) uvs + default_uvs_offset));
3068 nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3069 if (nranges > ((uvs_len - default_uvs_offset
3070 - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3071 / sizeof (struct unicode_value_range)))
3072 goto finish;
3073 /* Now 2 * nranges can't overflow, so we can safely use
3074 `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3075 mac_font_get_glyphs_for_variants. */
3076 }
3077
3078 non_default_uvs_offset =
3079 BUINT32_VALUE (records[i].non_default_uvs_offset);
3080 if (non_default_uvs_offset)
3081 {
3082 struct non_default_uvs_table *non_default_uvs;
3083 UInt32 nmappings;
3084
3085 if (non_default_uvs_offset > uvs_len
3086 || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3087 > uvs_len - non_default_uvs_offset))
3088 goto finish;
3089
3090 non_default_uvs = ((struct non_default_uvs_table *)
3091 ((UInt8 *) uvs + non_default_uvs_offset));
3092 nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3093 if (nmappings > ((uvs_len - non_default_uvs_offset
3094 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3095 / sizeof (struct uvs_mapping)))
3096 goto finish;
3097 /* Now 2 * nmappings can't overflow, so we can safely
3098 use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3099 in mac_font_get_glyphs_for_variants. */
3100 }
3101 }
3102
3103 uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3104
3105 finish:
3106 CFRelease (cmap_table);
3107 }
3108
3109 return uvs_table;
3110 }
3111
3112 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3113 sequence consisting of the given base character C and each
3114 variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3115 result (explained below) into the corresponding GLYPHS[i]. If the
3116 entry is found in the Default UVS Table, then the result is 0. If
3117 the entry is found in the Non-Default UVS Table, then the result is
3118 the associated glyph ID. Otherwise, kCGFontIndexInvalid. The
3119 elements in SELECTORS must be sorted in strictly increasing
3120 order. */
3121
3122 static void
3123 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3124 const UTF32Char selectors[], CGGlyph glyphs[],
3125 CFIndex count)
3126 {
3127 struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3128 struct variation_selector_record *records = uvs->variation_selector_records;
3129 CFIndex i;
3130 UInt32 ir, nrecords;
3131 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3132 dispatch_queue_t queue =
3133 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3134 dispatch_group_t group = dispatch_group_create ();
3135 #endif
3136
3137 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3138 i = 0;
3139 ir = 0;
3140 while (i < count && ir < nrecords)
3141 {
3142 UInt32 default_uvs_offset, non_default_uvs_offset;
3143
3144 if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3145 {
3146 glyphs[i++] = kCGFontIndexInvalid;
3147 continue;
3148 }
3149 else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3150 {
3151 ir++;
3152 continue;
3153 }
3154
3155 /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3156 default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3157 non_default_uvs_offset =
3158 BUINT32_VALUE (records[ir].non_default_uvs_offset);
3159 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3160 dispatch_group_async (group, queue, ^{
3161 #endif
3162 glyphs[i] = kCGFontIndexInvalid;
3163
3164 if (default_uvs_offset)
3165 {
3166 struct default_uvs_table *default_uvs =
3167 (struct default_uvs_table *) ((UInt8 *) uvs
3168 + default_uvs_offset);
3169 struct unicode_value_range *ranges =
3170 default_uvs->unicode_value_ranges;
3171 UInt32 lo, hi;
3172
3173 lo = 0;
3174 hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3175 while (lo < hi)
3176 {
3177 UInt32 mid = (lo + hi) / 2;
3178
3179 if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3180 hi = mid;
3181 else
3182 lo = mid + 1;
3183 }
3184 if (hi > 0
3185 && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3186 + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3187 glyphs[i] = 0;
3188 }
3189
3190 if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3191 {
3192 struct non_default_uvs_table *non_default_uvs =
3193 (struct non_default_uvs_table *) ((UInt8 *) uvs
3194 + non_default_uvs_offset);
3195 struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3196 UInt32 lo, hi;
3197
3198 lo = 0;
3199 hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3200 while (lo < hi)
3201 {
3202 UInt32 mid = (lo + hi) / 2;
3203
3204 if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3205 hi = mid;
3206 else
3207 lo = mid + 1;
3208 }
3209 if (hi > 0 &&
3210 BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3211 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3212 }
3213 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3214 });
3215 #endif
3216 i++;
3217 ir++;
3218 }
3219 while (i < count)
3220 glyphs[i++] = kCGFontIndexInvalid;
3221 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3222 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3223 dispatch_release (group);
3224 #endif
3225 }
3226
3227 static int
3228 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3229 {
3230 CFDataRef uvs_table;
3231 CharacterCollection uvs_collection;
3232 int i, n = 0;
3233
3234 block_input ();
3235 uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3236
3237 if (uvs_table)
3238 {
3239 UTF32Char selectors[256];
3240 CGGlyph glyphs[256];
3241
3242 for (i = 0; i < 16; i++)
3243 selectors[i] = 0xFE00 + i;
3244 for (; i < 256; i++)
3245 selectors[i] = 0xE0100 + (i - 16);
3246 mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3247 for (i = 0; i < 256; i++)
3248 {
3249 CGGlyph glyph = glyphs[i];
3250
3251 if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3252 && glyph != kCGFontIndexInvalid)
3253 glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3254 if (glyph == kCGFontIndexInvalid)
3255 variations[i] = 0;
3256 else
3257 {
3258 variations[i] = (glyph ? glyph
3259 : macfont_get_glyph_for_character (font, c));
3260 n++;
3261 }
3262 }
3263 }
3264 unblock_input ();
3265
3266 return n;
3267 }
3268
3269 static const char *const macfont_booleans[] = {
3270 ":antialias",
3271 ":minspace",
3272 NULL,
3273 };
3274
3275 static const char *const macfont_non_booleans[] = {
3276 ":lang",
3277 ":script",
3278 ":destination",
3279 NULL,
3280 };
3281
3282 static void
3283 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3284 {
3285 font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3286 }
3287
3288 static Boolean
3289 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3290 CFArrayRef languages)
3291 {
3292 Boolean result = true;
3293 CFArrayRef desc_languages =
3294 CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3295
3296 if (desc_languages == NULL)
3297 result = false;
3298 else
3299 {
3300 CFIndex desc_languages_count, i, languages_count;
3301
3302 desc_languages_count = CFArrayGetCount (desc_languages);
3303 languages_count = CFArrayGetCount (languages);
3304 for (i = 0; i < languages_count; i++)
3305 if (!CFArrayContainsValue (desc_languages,
3306 CFRangeMake (0, desc_languages_count),
3307 CFArrayGetValueAtIndex (languages, i)))
3308 {
3309 result = false;
3310 break;
3311 }
3312 CFRelease (desc_languages);
3313 }
3314
3315 return result;
3316 }
3317
3318 static CFStringRef
3319 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3320 {
3321 CFStringRef result = NULL;
3322 CFStringRef charset_string =
3323 CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3324 CFIndex length;
3325
3326 if (charset_string
3327 && (length = CFStringGetLength (charset_string)) > 0)
3328 {
3329 CFAttributedStringRef attr_string = NULL;
3330 CTLineRef ctline = NULL;
3331 CFDictionaryRef attrs =
3332 CFDictionaryCreate (NULL, NULL, NULL, 0,
3333 &kCFTypeDictionaryKeyCallBacks,
3334 &kCFTypeDictionaryValueCallBacks);
3335
3336 if (attrs)
3337 {
3338 attr_string = CFAttributedStringCreate (NULL, charset_string, attrs);
3339 CFRelease (attrs);
3340 }
3341 if (attr_string)
3342 {
3343 ctline = CTLineCreateWithAttributedString (attr_string);
3344 CFRelease (attr_string);
3345 }
3346 if (ctline)
3347 {
3348 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3349 CFIndex i, nruns = CFArrayGetCount (runs);
3350 CTFontRef font;
3351
3352 for (i = 0; i < nruns; i++)
3353 {
3354 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3355 CFDictionaryRef attributes = CTRunGetAttributes (run);
3356 CTFontRef font_in_run;
3357
3358 if (attributes == NULL)
3359 break;
3360 font_in_run =
3361 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3362 if (font_in_run == NULL)
3363 break;
3364 if (i == 0)
3365 font = font_in_run;
3366 else if (!mac_ctfont_equal_in_postscript_name (font, font_in_run))
3367 break;
3368 }
3369 if (nruns > 0 && i == nruns)
3370 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3371 CFRelease (ctline);
3372 }
3373 }
3374
3375 return result;
3376 }
3377
3378 static inline double
3379 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3380 {
3381 return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3382 &glyph, NULL, 1);
3383 }
3384
3385 static inline CGRect
3386 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3387 {
3388 return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3389 &glyph, NULL, 1);
3390 }
3391
3392 static CFArrayRef
3393 mac_ctfont_create_available_families (void)
3394 {
3395 CFMutableArrayRef families = NULL;
3396
3397 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3398 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3399 if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3400 #endif
3401 {
3402 CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3403
3404 if (orig_families)
3405 {
3406 CFIndex i, count = CFArrayGetCount (orig_families);
3407
3408 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3409 if (families)
3410 for (i = 0; i < count; i++)
3411 {
3412 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3413
3414 if (!CFStringHasPrefix (family, CFSTR ("."))
3415 && (CTFontManagerCompareFontFamilyNames (family,
3416 CFSTR ("LastResort"),
3417 NULL)
3418 != kCFCompareEqualTo))
3419 CFArrayAppendValue (families, family);
3420 }
3421 CFRelease (orig_families);
3422 }
3423 }
3424 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3425 else /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3426 #endif
3427 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3428 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3429 {
3430 CTFontCollectionRef collection;
3431 CFArrayRef descs = NULL;
3432
3433 collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3434 if (collection)
3435 {
3436 descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3437 CFRelease (collection);
3438 }
3439 if (descs)
3440 {
3441 CFIndex i, count = CFArrayGetCount (descs);
3442
3443 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3444 if (families)
3445 for (i = 0; i < count; i++)
3446 {
3447 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3448 CFStringRef name =
3449 mac_font_descriptor_copy_attribute (desc,
3450 MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3451
3452 if (name)
3453 {
3454 CFIndex p, limit = CFArrayGetCount (families);
3455
3456 p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3457 (const void *) name,
3458 mac_font_family_compare, NULL);
3459 if (p >= limit)
3460 CFArrayAppendValue (families, name);
3461 else if (mac_font_family_compare
3462 (CFArrayGetValueAtIndex (families, p),
3463 name, NULL) != kCFCompareEqualTo)
3464 CFArrayInsertValueAtIndex (families, p, name);
3465 CFRelease (name);
3466 }
3467 }
3468 CFRelease (descs);
3469 }
3470 }
3471 #endif
3472
3473 return families;
3474 }
3475
3476 static Boolean
3477 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3478 {
3479 Boolean result;
3480 CFStringRef name1, name2;
3481
3482 if (font1 == font2)
3483 return true;
3484
3485 result = false;
3486 name1 = CTFontCopyPostScriptName (font1);
3487 if (name1)
3488 {
3489 name2 = CTFontCopyPostScriptName (font2);
3490 if (name2)
3491 {
3492 result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3493 CFRelease (name2);
3494 }
3495 CFRelease (name1);
3496 }
3497
3498 return result;
3499 }
3500
3501 static CTLineRef
3502 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3503 CTFontRef macfont)
3504 {
3505 CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3506 CFTypeRef values[] = {NULL, NULL};
3507 CFDictionaryRef attributes = NULL;
3508 CFAttributedStringRef attr_string = NULL;
3509 CTLineRef ctline = NULL;
3510 float float_zero = 0.0f;
3511
3512 values[0] = macfont;
3513 values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3514 if (values[1])
3515 {
3516 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3517 (const void **) values,
3518 sizeof (keys) / sizeof (keys[0]),
3519 &kCFTypeDictionaryKeyCallBacks,
3520 &kCFTypeDictionaryValueCallBacks);
3521 CFRelease (values[1]);
3522 }
3523 if (attributes)
3524 {
3525 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3526 CFRelease (attributes);
3527 }
3528 if (attr_string)
3529 {
3530 ctline = CTLineCreateWithAttributedString (attr_string);
3531 CFRelease (attr_string);
3532 }
3533 if (ctline)
3534 {
3535 /* Abandon if ctline contains some fonts other than the
3536 specified one. */
3537 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3538 CFIndex i, nruns = CFArrayGetCount (runs);
3539
3540 for (i = 0; i < nruns; i++)
3541 {
3542 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3543 CFDictionaryRef attributes = CTRunGetAttributes (run);
3544 CTFontRef font_in_run;
3545
3546 if (attributes == NULL)
3547 break;
3548 font_in_run =
3549 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3550 if (font_in_run == NULL)
3551 break;
3552 if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3553 break;
3554 }
3555 if (i < nruns)
3556 {
3557 CFRelease (ctline);
3558 ctline = NULL;
3559 }
3560 }
3561
3562 return ctline;
3563 }
3564
3565 CFIndex
3566 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3567 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3568 {
3569 CFIndex used, result = 0;
3570 CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3571
3572 if (ctline == NULL)
3573 return 0;
3574
3575 used = CTLineGetGlyphCount (ctline);
3576 if (used <= glyph_len)
3577 {
3578 CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3579 CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3580 CGFloat total_advance = 0;
3581 CFIndex total_glyph_count = 0;
3582
3583 for (k = 0; k < ctrun_count; k++)
3584 {
3585 CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3586 CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3587 struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3588 CFRange string_range, comp_range, range;
3589 CFIndex *permutation;
3590
3591 if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3592 permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3593 else
3594 permutation = NULL;
3595
3596 #define RIGHT_TO_LEFT_P permutation
3597
3598 /* Now the `comp_range' member of struct mac_glyph_layout is
3599 temporarily used as a work area such that:
3600 glbuf[i].comp_range.location =
3601 min {compRange[i + 1].location, ...,
3602 compRange[glyph_count - 1].location,
3603 maxRange (stringRangeForCTRun)}
3604 glbuf[i].comp_range.length = maxRange (compRange[i])
3605 where compRange[i] is the range of composed characters
3606 containing i-th glyph. */
3607 string_range = CTRunGetStringRange (ctrun);
3608 min_location = string_range.location + string_range.length;
3609 for (i = 0; i < glyph_count; i++)
3610 {
3611 struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3612 CFIndex glyph_index;
3613 CFRange rng;
3614
3615 if (!RIGHT_TO_LEFT_P)
3616 glyph_index = glyph_count - i - 1;
3617 else
3618 glyph_index = i;
3619 CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3620 &gl->string_index);
3621 rng =
3622 CFStringGetRangeOfComposedCharactersAtIndex (string,
3623 gl->string_index);
3624 gl->comp_range.location = min_location;
3625 gl->comp_range.length = rng.location + rng.length;
3626 if (rng.location < min_location)
3627 min_location = rng.location;
3628 }
3629
3630 /* Fill the `comp_range' member of struct mac_glyph_layout,
3631 and setup a permutation for right-to-left text. */
3632 comp_range = CFRangeMake (string_range.location, 0);
3633 range = CFRangeMake (0, 0);
3634 while (1)
3635 {
3636 struct mac_glyph_layout *gl =
3637 glbuf + range.location + range.length;
3638
3639 if (gl->comp_range.length
3640 > comp_range.location + comp_range.length)
3641 comp_range.length = gl->comp_range.length - comp_range.location;
3642 min_location = gl->comp_range.location;
3643 range.length++;
3644
3645 if (min_location >= comp_range.location + comp_range.length)
3646 {
3647 comp_range.length = min_location - comp_range.location;
3648 for (i = 0; i < range.length; i++)
3649 {
3650 glbuf[range.location + i].comp_range = comp_range;
3651 if (RIGHT_TO_LEFT_P)
3652 permutation[range.location + i] =
3653 range.location + range.length - i - 1;
3654 }
3655
3656 comp_range = CFRangeMake (min_location, 0);
3657 range.location += range.length;
3658 range.length = 0;
3659 if (range.location == glyph_count)
3660 break;
3661 }
3662 }
3663
3664 /* Then fill the remaining members. */
3665 for (range = CFRangeMake (0, 1); range.location < glyph_count;
3666 range.location++)
3667 {
3668 struct mac_glyph_layout *gl;
3669 CGPoint position;
3670
3671 if (!RIGHT_TO_LEFT_P)
3672 gl = glbuf + range.location;
3673 else
3674 {
3675 CFIndex src, dest;
3676
3677 src = glyph_count - 1 - range.location;
3678 dest = permutation[src];
3679 gl = glbuf + dest;
3680 if (src < dest)
3681 {
3682 CFIndex tmp = gl->string_index;
3683
3684 gl->string_index = glbuf[src].string_index;
3685 glbuf[src].string_index = tmp;
3686 }
3687 }
3688 CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3689
3690 CTRunGetPositions (ctrun, range, &position);
3691 gl->advance_delta = position.x - total_advance;
3692 gl->baseline_delta = position.y;
3693 gl->advance = (gl->advance_delta
3694 + CTRunGetTypographicBounds (ctrun, range,
3695 NULL, NULL, NULL));
3696 total_advance += gl->advance;
3697 }
3698
3699 if (RIGHT_TO_LEFT_P)
3700 xfree (permutation);
3701
3702 #undef RIGHT_TO_LEFT_P
3703
3704 total_glyph_count += glyph_count;
3705 }
3706
3707 result = used;
3708 }
3709 CFRelease (ctline);
3710
3711 return result;
3712 }
3713
3714 /* The function below seems to cause a memory leak for the CFString
3715 created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3716 10.6.3. For now, we use the NSGlyphInfo version instead. */
3717 #if USE_CT_GLYPH_INFO
3718 CGGlyph
3719 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3720 CGFontIndex cid)
3721 {
3722 CGGlyph result = kCGFontIndexInvalid;
3723 UniChar characters[] = {0xfffd};
3724 CFStringRef string;
3725 CFAttributedStringRef attr_string = NULL;
3726 CTLineRef ctline = NULL;
3727
3728 string = CFStringCreateWithCharacters (NULL, characters,
3729 sizeof (characters)
3730 / sizeof (characters[0]));
3731 if (string)
3732 {
3733 CTGlyphInfoRef glyph_info =
3734 CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3735 CFDictionaryRef attributes = NULL;
3736
3737 if (glyph_info)
3738 {
3739 CFStringRef keys[] = {kCTFontAttributeName,
3740 kCTGlyphInfoAttributeName};
3741 CFTypeRef values[] = {font, glyph_info};
3742
3743 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3744 (const void **) values,
3745 sizeof (keys) / sizeof (keys[0]),
3746 &kCFTypeDictionaryKeyCallBacks,
3747 &kCFTypeDictionaryValueCallBacks);
3748 CFRelease (glyph_info);
3749 }
3750 if (attributes)
3751 {
3752 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3753 CFRelease (attributes);
3754 }
3755 CFRelease (string);
3756 }
3757 if (attr_string)
3758 {
3759 ctline = CTLineCreateWithAttributedString (attr_string);
3760 CFRelease (attr_string);
3761 }
3762 if (ctline)
3763 {
3764 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3765
3766 if (CFArrayGetCount (runs) > 0)
3767 {
3768 CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3769 CFDictionaryRef attributes = CTRunGetAttributes (run);
3770
3771 if (attributes)
3772 {
3773 CTFontRef font_in_run =
3774 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3775
3776 if (font_in_run
3777 && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3778 {
3779 CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3780 if (result >= CTFontGetGlyphCount (font))
3781 result = kCGFontIndexInvalid;
3782 }
3783 }
3784 }
3785 CFRelease (ctline);
3786 }
3787
3788 return result;
3789 }
3790 #endif
3791
3792 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3793 static inline int
3794 mac_font_family_group (CFStringRef family)
3795 {
3796 if (CFStringHasPrefix (family, CFSTR ("#")))
3797 return 2;
3798 else
3799 {
3800 CFRange range;
3801
3802 range = CFStringFind (family, CFSTR ("Apple"),
3803 kCFCompareCaseInsensitive | kCFCompareAnchored);
3804 if (range.location != kCFNotFound)
3805 return 1;
3806
3807 return 0;
3808 }
3809 }
3810
3811 CFComparisonResult
3812 mac_font_family_compare (const void *val1, const void *val2, void *context)
3813 {
3814 CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3815 int group1, group2;
3816
3817 group1 = mac_font_family_group (family1);
3818 group2 = mac_font_family_group (family2);
3819 if (group1 < group2)
3820 return kCFCompareLessThan;
3821 if (group1 > group2)
3822 return kCFCompareGreaterThan;
3823 return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3824 }
3825 #endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3826
3827 void *
3828 macfont_get_nsctfont (struct font *font)
3829 {
3830 struct macfont_info *macfont_info = (struct macfont_info *) font;
3831 FontRef macfont = macfont_info->macfont;
3832
3833 return (void *) macfont;
3834 }
3835
3836 void
3837 mac_register_font_driver (struct frame *f)
3838 {
3839 register_font_driver (&macfont_driver, f);
3840 }
3841
3842 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3843
3844 \f
3845 void
3846 syms_of_macfont (void)
3847 {
3848 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3849 static struct font_driver mac_font_driver;
3850
3851 DEFSYM (Qmac_ct, "mac-ct");
3852 macfont_driver.type = Qmac_ct;
3853 register_font_driver (&macfont_driver, NULL);
3854
3855 DEFSYM (QCdestination, ":destination");
3856 DEFSYM (QCminspace, ":minspace");
3857 #endif
3858 }