* lisp/progmodes/ruby-mode.el (ruby-mode-menu): Use proper
[bpt/emacs.git] / src / macfont.m
CommitLineData
d93ab42e
JD
1/* Font driver on Mac OSX Core text.
2 Copyright (C) 2009-2013 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
18
19Original 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
42static struct font_driver macfont_driver;
43
44/* Core Text, for Mac OS X 10.5 and later. */
45static Lisp_Object Qmac_ct;
46
47static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
48static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
49static CFArrayRef mac_ctfont_create_available_families (void);
50static Boolean mac_ctfont_equal_in_postscript_name (CTFontRef, CTFontRef);
51static CTLineRef mac_ctfont_create_line_with_string_and_font (CFStringRef,
52 CTFontRef);
53static CFComparisonResult mac_font_family_compare (const void *,
54 const void *, void *);
55static Boolean mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef,
56 CFArrayRef);
57static CFStringRef mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef);
58static CFIndex mac_ctfont_shape (CTFontRef, CFStringRef,
59 struct mac_glyph_layout *, CFIndex);
60#if USE_CT_GLYPH_INFO
61static 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. */
72static Lisp_Object QCdestination;
73
74/* The boolean-valued font property key specifying the use of
75 leading. */
76static Lisp_Object QCminspace;
77
78struct macfont_metrics;
79
80/* The actual structure for Mac font that can be casted to struct font. */
81
82struct 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
100enum
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
109enum
110 {
111 MACFONT_ANTIALIAS_DEFAULT,
112 MACFONT_ANTIALIAS_OFF,
113 MACFONT_ANTIALIAS_ON,
114 };
115
116enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
117enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200}; /* FC_WEIGHT_BOLD */
118enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
119
120static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
121static const CGFloat synthetic_bold_factor = 0.024;
122
123static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
124 FontSymbolicTraits *);
125static void macfont_store_descriptor_attributes (FontDescriptorRef,
126 Lisp_Object);
127static Lisp_Object macfont_descriptor_entity (FontDescriptorRef,
128 Lisp_Object,
129 FontSymbolicTraits);
130static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
131static int macfont_glyph_extents (struct font *, CGGlyph,
132 struct font_metrics *, CGFloat *, int);
133static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
134static Boolean macfont_supports_charset_and_languages_p (FontDescriptorRef,
135 CFCharacterSetRef,
136 Lisp_Object,
137 CFArrayRef);
138static CFIndex macfont_closest_traits_index (CFArrayRef,
139 FontSymbolicTraits);
140static CFDataRef mac_font_copy_uvs_table (FontRef);
141static 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
147static Lisp_Object
148cfdata_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
163static Lisp_Object
164cfstring_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
197static CFStringRef
198cfstring_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
211static CGFloat
212mac_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
219static CGGlyph
220mac_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
274static ScreenFontRef
275mac_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
286static Boolean
287mac_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
336static CFIndex
337mac_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
600static CFIndex
601mac_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
610static CGColorRef
611get_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
644static 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
696static CGFloat macfont_antialias_threshold;
697
698void
699macfont_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
712static inline Lisp_Object
713macfont_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
720static inline CFIndex
721macfont_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
739static Boolean
740cfnumber_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
757static void
758macfont_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
839static Lisp_Object
840macfont_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
883static CFStringRef
884macfont_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
958struct 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
980enum 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
996static int
997macfont_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
1134static 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
1145struct 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
1183static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1184static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1185static void macfont_release_cache (struct macfont_cache *);
1186static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1187static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1188static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1189static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1190 CharacterCollection, CGFontIndex);
1191static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1192
1193static struct macfont_cache *
1194macfont_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
1240static struct macfont_cache *
1241macfont_retain_cache (struct macfont_cache *cache)
1242{
1243 cache->reference_count++;
1244
1245 return cache;
1246}
1247
1248static void
1249macfont_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
1267static CFCharacterSetRef
1268macfont_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
1275static CFCharacterSetRef
1276macfont_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
1283static CGGlyph
1284macfont_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
1452static CGGlyph
1453macfont_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
1463static CFDataRef
1464macfont_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
1515static Lisp_Object macfont_get_cache (struct frame *);
1516static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1517static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1518static Lisp_Object macfont_list_family (struct frame *);
1519static void macfont_free_entity (Lisp_Object);
1520static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1521static void macfont_close (struct frame *, struct font *);
1522static int macfont_has_char (Lisp_Object, int);
1523static unsigned macfont_encode_char (struct font *, int);
1524static int macfont_text_extents (struct font *, unsigned int *, int,
1525 struct font_metrics *);
1526static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1527static Lisp_Object macfont_shape (Lisp_Object);
1528static int macfont_variation_glyphs (struct font *, int c,
1529 unsigned variations[256]);
1530static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1531
1532static 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
1564static Lisp_Object
1565macfont_get_cache (struct frame * f)
1566{
1567 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1568
1569 return (dpyinfo->name_list_element);
1570}
1571
1572static int
1573macfont_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
1633struct 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
1656static struct OpenTypeSpec *
1657macfont_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
1724static CFMutableDictionaryRef
1725macfont_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
1944static Boolean
1945macfont_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
1985static CFIndex
1986macfont_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
2019static Lisp_Object
2020macfont_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
2341static Lisp_Object
2342macfont_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
2374static Lisp_Object
2375macfont_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
2397static void
2398macfont_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
2409static Lisp_Object
2410macfont_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
2582static void
2583macfont_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
2602static int
2603macfont_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
2628static unsigned
2629macfont_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
2641static int
2642macfont_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
2676static int
2677macfont_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,
45435f08 2711 CGRectMake (x, y,
d93ab42e
JD
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;
c348360a 2723 int y_draw = -s->ybase;
d93ab42e
JD
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
2789Lisp_Object
2790macfont_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;
d93ab42e
JD
2820
2821 if (INT_MAX / 2 < len)
2822 memory_full (SIZE_MAX);
2823
2824 unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2825 nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2826 for (i = j = 0; i < len; i++)
2827 {
2828 UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2829
2830 if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2831 {
2832 nonbmp_indices[j] = i + j;
2833 j++;
2834 }
2835 }
2836 nonbmp_indices[j] = len + j; /* sentinel */
2837
2838 block_input ();
2839
2840 string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2841 kCFAllocatorNull);
2842 if (string)
2843 {
2844 glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2845 if (macfont_info->screen_font)
2846 used = mac_screen_font_shape (macfont_info->screen_font, string,
2847 glyph_layouts, glyph_len);
2848 else
2849 used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2850 CFRelease (string);
2851 }
2852
2853 unblock_input ();
2854
2855 if (used == 0)
2856 return Qnil;
2857
2858 block_input ();
2859
2860 for (i = 0; i < used; i++)
2861 {
2862 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2863 struct mac_glyph_layout *gl = glyph_layouts + i;
2864 EMACS_INT from, to;
2865 struct font_metrics metrics;
2866 int xoff, yoff, wadjust;
2867
2868 if (NILP (lglyph))
2869 {
2870 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2871 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2872 }
2873
2874 from = gl->comp_range.location;
2875 /* Convert UTF-16 index to UTF-32. */
2876 j = 0;
2877 while (nonbmp_indices[j] < from)
2878 j++;
2879 from -= j;
2880 LGLYPH_SET_FROM (lglyph, from);
2881
2882 to = gl->comp_range.location + gl->comp_range.length;
2883 /* Convert UTF-16 index to UTF-32. */
2884 while (nonbmp_indices[j] < to)
2885 j++;
2886 to -= j;
2887 LGLYPH_SET_TO (lglyph, to - 1);
2888
2889 /* LGLYPH_CHAR is used in `describe-char' for checking whether
2890 the composition is trivial. */
2891 {
2892 UTF32Char c;
2893
2894 if (unichars[gl->string_index] >= 0xD800
2895 && unichars[gl->string_index] < 0xDC00)
2896 c = (((unichars[gl->string_index] - 0xD800) << 10)
2897 + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2898 else
2899 c = unichars[gl->string_index];
2900 if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2901 c = 0;
2902 LGLYPH_SET_CHAR (lglyph, c);
2903 }
2904
2905 {
2906 unsigned long cc = gl->glyph_id;
2907 LGLYPH_SET_CODE (lglyph, cc);
2908 }
2909
2910 macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2911 LGLYPH_SET_WIDTH (lglyph, metrics.width);
2912 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2913 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2914 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2915 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2916
2917 xoff = lround (gl->advance_delta);
2918 yoff = lround (- gl->baseline_delta);
2919 wadjust = lround (gl->advance);
2920 if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2921 {
2922 Lisp_Object vec;
2923
2924 vec = Fmake_vector (make_number (3), Qnil);
2925 ASET (vec, 0, make_number (xoff));
2926 ASET (vec, 1, make_number (yoff));
2927 ASET (vec, 2, make_number (wadjust));
2928 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2929 }
2930 }
2931
2932 unblock_input ();
2933
2934 return make_number (used);
2935}
2936
2937/* Structures for the UVS subtable (format 14) in the cmap table. */
2938typedef UInt8 UINT24[3];
2939
2940#pragma pack(push, 1)
2941struct variation_selector_record
2942{
2943 UINT24 var_selector;
2944 UInt32 default_uvs_offset, non_default_uvs_offset;
2945};
2946struct uvs_table
2947{
2948 UInt16 format;
2949 UInt32 length, num_var_selector_records;
2950 struct variation_selector_record variation_selector_records[1];
2951};
2952#define SIZEOF_UVS_TABLE_HEADER \
2953 (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2954
2955struct unicode_value_range
2956{
2957 UINT24 start_unicode_value;
2958 UInt8 additional_count;
2959};
2960struct default_uvs_table {
2961 UInt32 num_unicode_value_ranges;
2962 struct unicode_value_range unicode_value_ranges[1];
2963};
2964#define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
2965 (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2966
2967struct uvs_mapping
2968{
2969 UINT24 unicode_value;
2970 UInt16 glyph_id;
2971};
2972struct non_default_uvs_table
2973{
2974 UInt32 num_uvs_mappings;
2975 struct uvs_mapping uvs_mappings[1];
2976};
2977#define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
2978 (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
2979#pragma pack(pop)
2980
2981/* Read big endian values. The argument LVAL must be an lvalue. */
2982/* I suppose OSReadBigInt* takes care of unaligned data. At least, we
2983 can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
2984 OSReadBigInt16(cdb, 7);" in a sample code by Apple. */
2985#define BUINT8_VALUE(lval) (*((UInt8 *) &(lval)))
2986#define BUINT16_VALUE(lval) OSReadBigInt16 (&(lval), 0)
2987/* Succeeding one byte should also be accessible. */
2988#define BUINT24_VALUE(lval) (OSReadBigInt32 (&(lval), 0) >> 8)
2989#define BUINT32_VALUE(lval) OSReadBigInt32 (&(lval), 0)
2990
2991/* Return UVS subtable for the specified FONT. If the subtable is not
2992 found or ill-formated, then return NULL. */
2993
2994static CFDataRef
2995mac_font_copy_uvs_table (FontRef font)
2996{
2997 CFDataRef cmap_table, uvs_table = NULL;
2998
2999 cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3000 if (cmap_table)
3001 {
3002 sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3003 struct uvs_table *uvs;
3004 struct variation_selector_record *records;
3005 UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3006
3007#if __LP64__
3008 if (CFDataGetLength (cmap_table) > UINT32_MAX)
3009 goto finish;
3010#endif
3011
3012 cmap_len = CFDataGetLength (cmap_table);
3013 if (sizeof_sfntCMapHeader > cmap_len)
3014 goto finish;
3015
3016 ntables = BUINT16_VALUE (cmap->numTables);
3017 if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3018 / sizeof_sfntCMapEncoding))
3019 goto finish;
3020
3021 for (i = 0; i < ntables; i++)
3022 if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3023 == kFontUnicodePlatform)
3024 && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3025 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3026 {
3027 uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3028 break;
3029 }
3030 if (i == ntables
3031 || uvs_offset > cmap_len
3032 || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3033 goto finish;
3034
3035 uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3036 uvs_len = BUINT32_VALUE (uvs->length);
3037 if (uvs_len > cmap_len - uvs_offset
3038 || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3039 goto finish;
3040
3041 if (BUINT16_VALUE (uvs->format) != 14)
3042 goto finish;
3043
3044 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3045 if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3046 / sizeof (struct variation_selector_record)))
3047 goto finish;
3048
3049 records = uvs->variation_selector_records;
3050 for (i = 0; i < nrecords; i++)
3051 {
3052 UInt32 default_uvs_offset, non_default_uvs_offset;
3053
3054 default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3055 if (default_uvs_offset)
3056 {
3057 struct default_uvs_table *default_uvs;
3058 UInt32 nranges;
3059
3060 if (default_uvs_offset > uvs_len
3061 || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3062 > uvs_len - default_uvs_offset))
3063 goto finish;
3064
3065 default_uvs = ((struct default_uvs_table *)
3066 ((UInt8 *) uvs + default_uvs_offset));
3067 nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3068 if (nranges > ((uvs_len - default_uvs_offset
3069 - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3070 / sizeof (struct unicode_value_range)))
3071 goto finish;
3072 /* Now 2 * nranges can't overflow, so we can safely use
3073 `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3074 mac_font_get_glyphs_for_variants. */
3075 }
3076
3077 non_default_uvs_offset =
3078 BUINT32_VALUE (records[i].non_default_uvs_offset);
3079 if (non_default_uvs_offset)
3080 {
3081 struct non_default_uvs_table *non_default_uvs;
3082 UInt32 nmappings;
3083
3084 if (non_default_uvs_offset > uvs_len
3085 || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3086 > uvs_len - non_default_uvs_offset))
3087 goto finish;
3088
3089 non_default_uvs = ((struct non_default_uvs_table *)
3090 ((UInt8 *) uvs + non_default_uvs_offset));
3091 nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3092 if (nmappings > ((uvs_len - non_default_uvs_offset
3093 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3094 / sizeof (struct uvs_mapping)))
3095 goto finish;
3096 /* Now 2 * nmappings can't overflow, so we can safely
3097 use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3098 in mac_font_get_glyphs_for_variants. */
3099 }
3100 }
3101
3102 uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3103
3104 finish:
3105 CFRelease (cmap_table);
3106 }
3107
3108 return uvs_table;
3109}
3110
3111/* Find an entry in the given UVS subtable UVS_TABLE for a variation
3112 sequence consisting of the given base character C and each
3113 variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3114 result (explained below) into the corresponding GLYPHS[i]. If the
3115 entry is found in the Default UVS Table, then the result is 0. If
3116 the entry is found in the Non-Default UVS Table, then the result is
3117 the associated glyph ID. Otherwise, kCGFontIndexInvalid. The
3118 elements in SELECTORS must be sorted in strictly increasing
3119 order. */
3120
3121static void
3122mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3123 const UTF32Char selectors[], CGGlyph glyphs[],
3124 CFIndex count)
3125{
3126 struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3127 struct variation_selector_record *records = uvs->variation_selector_records;
3128 CFIndex i;
3129 UInt32 ir, nrecords;
3130#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3131 dispatch_queue_t queue =
3132 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3133 dispatch_group_t group = dispatch_group_create ();
3134#endif
3135
3136 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3137 i = 0;
3138 ir = 0;
3139 while (i < count && ir < nrecords)
3140 {
3141 UInt32 default_uvs_offset, non_default_uvs_offset;
3142
3143 if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3144 {
3145 glyphs[i++] = kCGFontIndexInvalid;
3146 continue;
3147 }
3148 else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3149 {
3150 ir++;
3151 continue;
3152 }
3153
3154 /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3155 default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3156 non_default_uvs_offset =
3157 BUINT32_VALUE (records[ir].non_default_uvs_offset);
3158#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3159 dispatch_group_async (group, queue, ^{
3160#endif
3161 glyphs[i] = kCGFontIndexInvalid;
3162
3163 if (default_uvs_offset)
3164 {
3165 struct default_uvs_table *default_uvs =
3166 (struct default_uvs_table *) ((UInt8 *) uvs
3167 + default_uvs_offset);
3168 struct unicode_value_range *ranges =
3169 default_uvs->unicode_value_ranges;
3170 UInt32 lo, hi;
3171
3172 lo = 0;
3173 hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3174 while (lo < hi)
3175 {
3176 UInt32 mid = (lo + hi) / 2;
3177
3178 if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3179 hi = mid;
3180 else
3181 lo = mid + 1;
3182 }
3183 if (hi > 0
3184 && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3185 + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3186 glyphs[i] = 0;
3187 }
3188
3189 if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3190 {
3191 struct non_default_uvs_table *non_default_uvs =
3192 (struct non_default_uvs_table *) ((UInt8 *) uvs
3193 + non_default_uvs_offset);
3194 struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3195 UInt32 lo, hi;
3196
3197 lo = 0;
3198 hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3199 while (lo < hi)
3200 {
3201 UInt32 mid = (lo + hi) / 2;
3202
3203 if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3204 hi = mid;
3205 else
3206 lo = mid + 1;
3207 }
3208 if (hi > 0 &&
3209 BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3210 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3211 }
3212#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3213 });
3214#endif
3215 i++;
3216 ir++;
3217 }
3218 while (i < count)
3219 glyphs[i++] = kCGFontIndexInvalid;
3220#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3221 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3222 dispatch_release (group);
3223#endif
3224}
3225
3226static int
3227macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3228{
3229 CFDataRef uvs_table;
3230 CharacterCollection uvs_collection;
3231 int i, n = 0;
3232
3233 block_input ();
3234 uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3235
3236 if (uvs_table)
3237 {
3238 UTF32Char selectors[256];
3239 CGGlyph glyphs[256];
3240
3241 for (i = 0; i < 16; i++)
3242 selectors[i] = 0xFE00 + i;
3243 for (; i < 256; i++)
3244 selectors[i] = 0xE0100 + (i - 16);
3245 mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3246 for (i = 0; i < 256; i++)
3247 {
3248 CGGlyph glyph = glyphs[i];
3249
3250 if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3251 && glyph != kCGFontIndexInvalid)
3252 glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3253 if (glyph == kCGFontIndexInvalid)
3254 variations[i] = 0;
3255 else
3256 {
3257 variations[i] = (glyph ? glyph
3258 : macfont_get_glyph_for_character (font, c));
3259 n++;
3260 }
3261 }
3262 }
3263 unblock_input ();
3264
3265 return n;
3266}
3267
3268static const char *const macfont_booleans[] = {
3269 ":antialias",
3270 ":minspace",
3271 NULL,
3272};
3273
3274static const char *const macfont_non_booleans[] = {
3275 ":lang",
3276 ":script",
3277 ":destination",
3278 NULL,
3279};
3280
3281static void
3282macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3283{
3284 font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3285}
3286
3287static Boolean
3288mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3289 CFArrayRef languages)
3290{
3291 Boolean result = true;
3292 CFArrayRef desc_languages =
3293 CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3294
3295 if (desc_languages == NULL)
3296 result = false;
3297 else
3298 {
3299 CFIndex desc_languages_count, i, languages_count;
3300
3301 desc_languages_count = CFArrayGetCount (desc_languages);
3302 languages_count = CFArrayGetCount (languages);
3303 for (i = 0; i < languages_count; i++)
3304 if (!CFArrayContainsValue (desc_languages,
3305 CFRangeMake (0, desc_languages_count),
3306 CFArrayGetValueAtIndex (languages, i)))
3307 {
3308 result = false;
3309 break;
3310 }
3311 CFRelease (desc_languages);
3312 }
3313
3314 return result;
3315}
3316
3317static CFStringRef
3318mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3319{
3320 CFStringRef result = NULL;
3321 CFStringRef charset_string =
3322 CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
d93ab42e 3323
c348360a 3324 if (charset_string && CFStringGetLength (charset_string) > 0)
d93ab42e
JD
3325 {
3326 CFAttributedStringRef attr_string = NULL;
3327 CTLineRef ctline = NULL;
3328 CFDictionaryRef attrs =
3329 CFDictionaryCreate (NULL, NULL, NULL, 0,
3330 &kCFTypeDictionaryKeyCallBacks,
3331 &kCFTypeDictionaryValueCallBacks);
3332
3333 if (attrs)
3334 {
3335 attr_string = CFAttributedStringCreate (NULL, charset_string, attrs);
3336 CFRelease (attrs);
3337 }
3338 if (attr_string)
3339 {
3340 ctline = CTLineCreateWithAttributedString (attr_string);
3341 CFRelease (attr_string);
3342 }
3343 if (ctline)
3344 {
3345 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3346 CFIndex i, nruns = CFArrayGetCount (runs);
3347 CTFontRef font;
3348
3349 for (i = 0; i < nruns; i++)
3350 {
3351 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3352 CFDictionaryRef attributes = CTRunGetAttributes (run);
3353 CTFontRef font_in_run;
3354
3355 if (attributes == NULL)
3356 break;
3357 font_in_run =
3358 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3359 if (font_in_run == NULL)
3360 break;
3361 if (i == 0)
3362 font = font_in_run;
3363 else if (!mac_ctfont_equal_in_postscript_name (font, font_in_run))
3364 break;
3365 }
3366 if (nruns > 0 && i == nruns)
3367 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3368 CFRelease (ctline);
3369 }
3370 }
3371
3372 return result;
3373}
3374
3375static inline double
3376mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3377{
3378 return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3379 &glyph, NULL, 1);
3380}
3381
3382static inline CGRect
3383mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3384{
3385 return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3386 &glyph, NULL, 1);
3387}
3388
3389static CFArrayRef
3390mac_ctfont_create_available_families (void)
3391{
3392 CFMutableArrayRef families = NULL;
3393
3394#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3395#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3396 if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3397#endif
3398 {
3399 CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3400
3401 if (orig_families)
3402 {
3403 CFIndex i, count = CFArrayGetCount (orig_families);
3404
3405 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3406 if (families)
3407 for (i = 0; i < count; i++)
3408 {
3409 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3410
3411 if (!CFStringHasPrefix (family, CFSTR ("."))
3412 && (CTFontManagerCompareFontFamilyNames (family,
3413 CFSTR ("LastResort"),
3414 NULL)
3415 != kCFCompareEqualTo))
3416 CFArrayAppendValue (families, family);
3417 }
3418 CFRelease (orig_families);
3419 }
3420 }
3421#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3422 else /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3423#endif
3424#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3425#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3426 {
3427 CTFontCollectionRef collection;
3428 CFArrayRef descs = NULL;
3429
3430 collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3431 if (collection)
3432 {
3433 descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3434 CFRelease (collection);
3435 }
3436 if (descs)
3437 {
3438 CFIndex i, count = CFArrayGetCount (descs);
3439
3440 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3441 if (families)
3442 for (i = 0; i < count; i++)
3443 {
3444 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3445 CFStringRef name =
3446 mac_font_descriptor_copy_attribute (desc,
3447 MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3448
3449 if (name)
3450 {
3451 CFIndex p, limit = CFArrayGetCount (families);
3452
3453 p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3454 (const void *) name,
3455 mac_font_family_compare, NULL);
3456 if (p >= limit)
3457 CFArrayAppendValue (families, name);
3458 else if (mac_font_family_compare
3459 (CFArrayGetValueAtIndex (families, p),
3460 name, NULL) != kCFCompareEqualTo)
3461 CFArrayInsertValueAtIndex (families, p, name);
3462 CFRelease (name);
3463 }
3464 }
3465 CFRelease (descs);
3466 }
3467 }
3468#endif
3469
3470 return families;
3471}
3472
3473static Boolean
3474mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3475{
3476 Boolean result;
3477 CFStringRef name1, name2;
3478
3479 if (font1 == font2)
3480 return true;
3481
3482 result = false;
3483 name1 = CTFontCopyPostScriptName (font1);
3484 if (name1)
3485 {
3486 name2 = CTFontCopyPostScriptName (font2);
3487 if (name2)
3488 {
3489 result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3490 CFRelease (name2);
3491 }
3492 CFRelease (name1);
3493 }
3494
3495 return result;
3496}
3497
3498static CTLineRef
3499mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3500 CTFontRef macfont)
3501{
3502 CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3503 CFTypeRef values[] = {NULL, NULL};
3504 CFDictionaryRef attributes = NULL;
3505 CFAttributedStringRef attr_string = NULL;
3506 CTLineRef ctline = NULL;
3507 float float_zero = 0.0f;
3508
3509 values[0] = macfont;
3510 values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3511 if (values[1])
3512 {
3513 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3514 (const void **) values,
3515 sizeof (keys) / sizeof (keys[0]),
3516 &kCFTypeDictionaryKeyCallBacks,
3517 &kCFTypeDictionaryValueCallBacks);
3518 CFRelease (values[1]);
3519 }
3520 if (attributes)
3521 {
3522 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3523 CFRelease (attributes);
3524 }
3525 if (attr_string)
3526 {
3527 ctline = CTLineCreateWithAttributedString (attr_string);
3528 CFRelease (attr_string);
3529 }
3530 if (ctline)
3531 {
3532 /* Abandon if ctline contains some fonts other than the
3533 specified one. */
3534 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3535 CFIndex i, nruns = CFArrayGetCount (runs);
3536
3537 for (i = 0; i < nruns; i++)
3538 {
3539 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3540 CFDictionaryRef attributes = CTRunGetAttributes (run);
3541 CTFontRef font_in_run;
3542
3543 if (attributes == NULL)
3544 break;
3545 font_in_run =
3546 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3547 if (font_in_run == NULL)
3548 break;
3549 if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3550 break;
3551 }
3552 if (i < nruns)
3553 {
3554 CFRelease (ctline);
3555 ctline = NULL;
3556 }
3557 }
3558
3559 return ctline;
3560}
3561
3562CFIndex
3563mac_ctfont_shape (CTFontRef font, CFStringRef string,
3564 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3565{
3566 CFIndex used, result = 0;
3567 CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3568
3569 if (ctline == NULL)
3570 return 0;
3571
3572 used = CTLineGetGlyphCount (ctline);
3573 if (used <= glyph_len)
3574 {
3575 CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3576 CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3577 CGFloat total_advance = 0;
3578 CFIndex total_glyph_count = 0;
3579
3580 for (k = 0; k < ctrun_count; k++)
3581 {
3582 CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3583 CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3584 struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3585 CFRange string_range, comp_range, range;
3586 CFIndex *permutation;
3587
3588 if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3589 permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3590 else
3591 permutation = NULL;
3592
3593#define RIGHT_TO_LEFT_P permutation
3594
3595 /* Now the `comp_range' member of struct mac_glyph_layout is
3596 temporarily used as a work area such that:
3597 glbuf[i].comp_range.location =
3598 min {compRange[i + 1].location, ...,
3599 compRange[glyph_count - 1].location,
3600 maxRange (stringRangeForCTRun)}
3601 glbuf[i].comp_range.length = maxRange (compRange[i])
3602 where compRange[i] is the range of composed characters
3603 containing i-th glyph. */
3604 string_range = CTRunGetStringRange (ctrun);
3605 min_location = string_range.location + string_range.length;
3606 for (i = 0; i < glyph_count; i++)
3607 {
3608 struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3609 CFIndex glyph_index;
3610 CFRange rng;
3611
3612 if (!RIGHT_TO_LEFT_P)
3613 glyph_index = glyph_count - i - 1;
3614 else
3615 glyph_index = i;
3616 CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3617 &gl->string_index);
3618 rng =
3619 CFStringGetRangeOfComposedCharactersAtIndex (string,
3620 gl->string_index);
3621 gl->comp_range.location = min_location;
3622 gl->comp_range.length = rng.location + rng.length;
3623 if (rng.location < min_location)
3624 min_location = rng.location;
3625 }
3626
3627 /* Fill the `comp_range' member of struct mac_glyph_layout,
3628 and setup a permutation for right-to-left text. */
3629 comp_range = CFRangeMake (string_range.location, 0);
3630 range = CFRangeMake (0, 0);
3631 while (1)
3632 {
3633 struct mac_glyph_layout *gl =
3634 glbuf + range.location + range.length;
3635
3636 if (gl->comp_range.length
3637 > comp_range.location + comp_range.length)
3638 comp_range.length = gl->comp_range.length - comp_range.location;
3639 min_location = gl->comp_range.location;
3640 range.length++;
3641
3642 if (min_location >= comp_range.location + comp_range.length)
3643 {
3644 comp_range.length = min_location - comp_range.location;
3645 for (i = 0; i < range.length; i++)
3646 {
3647 glbuf[range.location + i].comp_range = comp_range;
3648 if (RIGHT_TO_LEFT_P)
3649 permutation[range.location + i] =
3650 range.location + range.length - i - 1;
3651 }
3652
3653 comp_range = CFRangeMake (min_location, 0);
3654 range.location += range.length;
3655 range.length = 0;
3656 if (range.location == glyph_count)
3657 break;
3658 }
3659 }
3660
3661 /* Then fill the remaining members. */
3662 for (range = CFRangeMake (0, 1); range.location < glyph_count;
3663 range.location++)
3664 {
3665 struct mac_glyph_layout *gl;
3666 CGPoint position;
3667
3668 if (!RIGHT_TO_LEFT_P)
3669 gl = glbuf + range.location;
3670 else
3671 {
3672 CFIndex src, dest;
3673
3674 src = glyph_count - 1 - range.location;
3675 dest = permutation[src];
3676 gl = glbuf + dest;
3677 if (src < dest)
3678 {
3679 CFIndex tmp = gl->string_index;
3680
3681 gl->string_index = glbuf[src].string_index;
3682 glbuf[src].string_index = tmp;
3683 }
3684 }
3685 CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3686
3687 CTRunGetPositions (ctrun, range, &position);
3688 gl->advance_delta = position.x - total_advance;
3689 gl->baseline_delta = position.y;
3690 gl->advance = (gl->advance_delta
3691 + CTRunGetTypographicBounds (ctrun, range,
3692 NULL, NULL, NULL));
3693 total_advance += gl->advance;
3694 }
3695
3696 if (RIGHT_TO_LEFT_P)
3697 xfree (permutation);
3698
3699#undef RIGHT_TO_LEFT_P
3700
3701 total_glyph_count += glyph_count;
3702 }
3703
3704 result = used;
3705 }
3706 CFRelease (ctline);
3707
3708 return result;
3709}
3710
3711/* The function below seems to cause a memory leak for the CFString
3712 created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3713 10.6.3. For now, we use the NSGlyphInfo version instead. */
3714#if USE_CT_GLYPH_INFO
3715CGGlyph
3716mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3717 CGFontIndex cid)
3718{
3719 CGGlyph result = kCGFontIndexInvalid;
3720 UniChar characters[] = {0xfffd};
3721 CFStringRef string;
3722 CFAttributedStringRef attr_string = NULL;
3723 CTLineRef ctline = NULL;
3724
3725 string = CFStringCreateWithCharacters (NULL, characters,
3726 sizeof (characters)
3727 / sizeof (characters[0]));
3728 if (string)
3729 {
3730 CTGlyphInfoRef glyph_info =
3731 CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3732 CFDictionaryRef attributes = NULL;
3733
3734 if (glyph_info)
3735 {
3736 CFStringRef keys[] = {kCTFontAttributeName,
3737 kCTGlyphInfoAttributeName};
3738 CFTypeRef values[] = {font, glyph_info};
3739
3740 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3741 (const void **) values,
3742 sizeof (keys) / sizeof (keys[0]),
3743 &kCFTypeDictionaryKeyCallBacks,
3744 &kCFTypeDictionaryValueCallBacks);
3745 CFRelease (glyph_info);
3746 }
3747 if (attributes)
3748 {
3749 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3750 CFRelease (attributes);
3751 }
3752 CFRelease (string);
3753 }
3754 if (attr_string)
3755 {
3756 ctline = CTLineCreateWithAttributedString (attr_string);
3757 CFRelease (attr_string);
3758 }
3759 if (ctline)
3760 {
3761 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3762
3763 if (CFArrayGetCount (runs) > 0)
3764 {
3765 CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3766 CFDictionaryRef attributes = CTRunGetAttributes (run);
3767
3768 if (attributes)
3769 {
3770 CTFontRef font_in_run =
3771 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3772
3773 if (font_in_run
3774 && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3775 {
3776 CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3777 if (result >= CTFontGetGlyphCount (font))
3778 result = kCGFontIndexInvalid;
3779 }
3780 }
3781 }
3782 CFRelease (ctline);
3783 }
3784
3785 return result;
3786}
3787#endif
3788
3789#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3790static inline int
3791mac_font_family_group (CFStringRef family)
3792{
3793 if (CFStringHasPrefix (family, CFSTR ("#")))
3794 return 2;
3795 else
3796 {
3797 CFRange range;
3798
3799 range = CFStringFind (family, CFSTR ("Apple"),
3800 kCFCompareCaseInsensitive | kCFCompareAnchored);
3801 if (range.location != kCFNotFound)
3802 return 1;
3803
3804 return 0;
3805 }
3806}
3807
3808CFComparisonResult
3809mac_font_family_compare (const void *val1, const void *val2, void *context)
3810{
3811 CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3812 int group1, group2;
3813
3814 group1 = mac_font_family_group (family1);
3815 group2 = mac_font_family_group (family2);
3816 if (group1 < group2)
3817 return kCFCompareLessThan;
3818 if (group1 > group2)
3819 return kCFCompareGreaterThan;
3820 return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3821}
3822#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3823
3824void *
3825macfont_get_nsctfont (struct font *font)
3826{
3827 struct macfont_info *macfont_info = (struct macfont_info *) font;
3828 FontRef macfont = macfont_info->macfont;
3829
3830 return (void *) macfont;
3831}
3832
3833void
3834mac_register_font_driver (struct frame *f)
3835{
3836 register_font_driver (&macfont_driver, f);
3837}
3838
3839#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3840
3841\f
3842void
3843syms_of_macfont (void)
3844{
3845#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
3846 static struct font_driver mac_font_driver;
3847
3848 DEFSYM (Qmac_ct, "mac-ct");
3849 macfont_driver.type = Qmac_ct;
3850 register_font_driver (&macfont_driver, NULL);
3851
3852 DEFSYM (QCdestination, ":destination");
3853 DEFSYM (QCminspace, ":minspace");
3854#endif
3855}