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