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