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