Clean up array size calculations
[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
705cf384 240 length:EARRAYSIZE (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
779 OS 10.6 when the value is greater than or equal to 1 << 31. */
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
705cf384 828 for (i = 0; i < EARRAYSIZE (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. */
1254 if (CFStringCompare (key, CFSTR ("LastResort"), 0)
1255 == kCFCompareEqualTo)
1256 {
1257 CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1258
1259 cache->cf_charset =
1260 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1261 }
1262 if (cache->cf_charset == NULL)
1263 cache->cf_charset = mac_font_copy_character_set (macfont);
1264 CFDictionaryAddValue (macfont_cache_dictionary, key,
1265 (const void *) cache);
1266 CFRelease (macfont);
1267 }
1268 }
1269
1270 return cache;
1271}
1272
1273static struct macfont_cache *
1274macfont_retain_cache (struct macfont_cache *cache)
1275{
1276 cache->reference_count++;
1277
1278 return cache;
1279}
1280
1281static void
1282macfont_release_cache (struct macfont_cache *cache)
1283{
1284 if (--cache->reference_count == 0)
1285 {
1286 int i;
1287
1288 for (i = 0; i < cache->glyph.nrows; i++)
1289 xfree (cache->glyph.matrix[i]);
1290 xfree (cache->glyph.matrix);
1291 if (cache->glyph.dictionary)
1292 CFRelease (cache->glyph.dictionary);
1293 memset (&cache->glyph, 0, sizeof (cache->glyph));
1294 if (cache->uvs.table)
1295 CFRelease (cache->uvs.table);
1296 memset (&cache->uvs, 0, sizeof (cache->uvs));
1297 }
1298}
1299
1300static CFCharacterSetRef
1301macfont_get_cf_charset (struct font *font)
1302{
1303 struct macfont_info *macfont_info = (struct macfont_info *) font;
1304
1305 return macfont_info->cache->cf_charset;
1306}
1307
1308static CFCharacterSetRef
1309macfont_get_cf_charset_for_name (CFStringRef name)
1310{
1311 struct macfont_cache *cache = macfont_lookup_cache (name);
1312
1313 return cache->cf_charset;
1314}
1315
1316static CGGlyph
1317macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1318{
1319 struct macfont_info *macfont_info = (struct macfont_info *) font;
1320 FontRef macfont = macfont_info->macfont;
1321 struct macfont_cache *cache = macfont_info->cache;
1322
1323 if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1324 {
1325 int row = c / 256;
1326 int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1327
1328 if (nkeys_or_perm < ROW_PERM_OFFSET)
1329 {
1330 UniChar unichars[256], ch;
1331 CGGlyph *glyphs;
1332 int i, len;
1333 int nrows;
1334#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1335 dispatch_queue_t queue;
1336 dispatch_group_t group = NULL;
1337#else
1338 int nkeys;
1339#endif
1340
1341 if (row != 0)
1342 {
1343 CFMutableDictionaryRef dictionary;
1344 uintptr_t key, value;
1345 int nshifts;
1346 CGGlyph glyph;
1347
1348 if (cache->glyph.dictionary == NULL)
1349 cache->glyph.dictionary =
1350 CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1351 dictionary = cache->glyph.dictionary;
1352 key = c / NGLYPHS_IN_VALUE;
1353 nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1354 value = ((uintptr_t)
1355 CFDictionaryGetValue (dictionary, (const void *) key));
1356 glyph = (value >> nshifts);
1357 if (glyph)
1358 return glyph;
1359
1360 if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1361 {
1362 ch = c;
1363 if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1364 &glyph, 1)
1365 || glyph == 0)
1366 glyph = kCGFontIndexInvalid;
1367
1368 if (value == 0)
1369 cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1370 value |= ((uintptr_t) glyph << nshifts);
1371 CFDictionarySetValue (dictionary, (const void *) key,
1372 (const void *) value);
1373
1374 return glyph;
1375 }
1376
1377#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1378 queue =
1379 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1380 group = dispatch_group_create ();
1381 dispatch_group_async (group, queue, ^{
1382 int nkeys;
1383 uintptr_t key;
1384#endif
1385 nkeys = nkeys_or_perm;
1386 for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1387 if (CFDictionaryContainsKey (dictionary,
1388 (const void *) key))
1389 {
1390 CFDictionaryRemoveValue (dictionary,
1391 (const void *) key);
1392 if (--nkeys == 0)
1393 break;
1394 }
1395#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1396 });
1397#endif
1398 }
1399
1400 len = 0;
1401 for (i = 0; i < 256; i++)
1402 {
1403 ch = row * 256 + i;
1404 if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1405 unichars[len++] = ch;
1406 }
1407
1408 glyphs = xmalloc (sizeof (CGGlyph) * 256);
1409 if (len > 0)
1410 {
1411 mac_font_get_glyphs_for_characters (macfont, unichars,
1412 glyphs, len);
1413 while (i > len)
1414 {
1415 int next = unichars[len - 1] % 256;
1416
1417 while (--i > next)
1418 glyphs[i] = kCGFontIndexInvalid;
1419
1420 len--;
1421 glyphs[i] = glyphs[len];
1422 if (len == 0)
1423 break;
1424 }
1425 }
1426 if (i > len)
1427 while (i-- > 0)
1428 glyphs[i] = kCGFontIndexInvalid;
1429
1430 nrows = cache->glyph.nrows;
1431 nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1432 cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1433 nrows++;
1434 cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1435 sizeof (CGGlyph *) * nrows);
1436 cache->glyph.matrix[nrows - 1] = glyphs;
1437 cache->glyph.nrows = nrows;
1438
1439#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1440 if (group)
1441 {
1442 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1443 dispatch_release (group);
1444 }
1445#endif
1446 }
1447
1448 return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1449 }
1450 else
1451 {
1452 uintptr_t key, value;
1453 int nshifts;
1454 CGGlyph glyph;
1455
1456 if (cache->glyph.dictionary == NULL)
1457 cache->glyph.dictionary =
1458 CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1459 key = c / NGLYPHS_IN_VALUE;
1460 nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1461 value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1462 (const void *) key);
1463 glyph = (value >> nshifts);
1464 if (glyph == 0)
1465 {
1466 UniChar unichars[2];
1467 CGGlyph glyphs[2];
1468 CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1469
1470 if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1471 count))
1472 glyph = glyphs[0];
1473 if (glyph == 0)
1474 glyph = kCGFontIndexInvalid;
1475
1476 value |= ((uintptr_t) glyph << nshifts);
1477 CFDictionarySetValue (cache->glyph.dictionary,
1478 (const void *) key, (const void *) value);
1479 }
1480
1481 return glyph;
1482 }
1483}
1484
1485static CGGlyph
1486macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1487 CGFontIndex cid)
1488{
1489 struct macfont_info *macfont_info = (struct macfont_info *) font;
1490 FontRef macfont = macfont_info->macfont;
1491
1492 /* Cache it? */
1493 return mac_font_get_glyph_for_cid (macfont, collection, cid);
1494}
1495
1496static CFDataRef
1497macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1498{
1499 struct macfont_info *macfont_info = (struct macfont_info *) font;
1500 FontRef macfont = macfont_info->macfont;
1501 struct macfont_cache *cache = macfont_info->cache;
1502 CFDataRef result = NULL;
1503
1504 if (cache->uvs.table == NULL)
1505 {
1506 CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1507 CharacterCollection uvs_collection =
1508 MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1509
1510 if (uvs_table == NULL
1511 && mac_font_get_glyph_for_cid (macfont,
1512 MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1513 6480) != kCGFontIndexInvalid)
1514 {
1515 /* If the glyph for U+4E55 is accessible via its CID 6480,
1516 then we use the Adobe-Japan1 UVS table, which maps a
1517 variation sequence to a CID, as a fallback. */
1518 static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1519
1520 if (mac_uvs_table_adobe_japan1 == NULL)
1521 mac_uvs_table_adobe_japan1 =
1522 CFDataCreateWithBytesNoCopy (NULL,
1523 mac_uvs_table_adobe_japan1_bytes,
1524 sizeof (mac_uvs_table_adobe_japan1_bytes),
1525 kCFAllocatorNull);
1526 if (mac_uvs_table_adobe_japan1)
1527 {
1528 uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1529 uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1530 }
1531 }
1532 if (uvs_table == NULL)
1533 cache->uvs.table = kCFNull;
1534 else
1535 cache->uvs.table = uvs_table;
1536 cache->uvs.collection = uvs_collection;
1537 }
1538
1539 if (cache->uvs.table != kCFNull)
1540 {
1541 result = cache->uvs.table;
1542 *collection = cache->uvs.collection;
1543 }
1544
1545 return result;
1546}
1547
1548static Lisp_Object macfont_get_cache (struct frame *);
1549static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1550static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1551static Lisp_Object macfont_list_family (struct frame *);
1552static void macfont_free_entity (Lisp_Object);
1553static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
78e0b35c 1554static void macfont_close (struct font *);
d93ab42e
JD
1555static int macfont_has_char (Lisp_Object, int);
1556static unsigned macfont_encode_char (struct font *, int);
1557static int macfont_text_extents (struct font *, unsigned int *, int,
1558 struct font_metrics *);
1559static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1560static Lisp_Object macfont_shape (Lisp_Object);
1561static int macfont_variation_glyphs (struct font *, int c,
1562 unsigned variations[256]);
1563static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1564
1565static struct font_driver macfont_driver =
1566 {
1567 LISP_INITIALLY_ZERO, /* Qmac_ct */
1568 0, /* case insensitive */
1569 macfont_get_cache,
1570 macfont_list,
1571 macfont_match,
1572 macfont_list_family,
1573 macfont_free_entity,
1574 macfont_open,
1575 macfont_close,
1576 NULL, /* prepare_face */
1577 NULL, /* done_face */
1578 macfont_has_char,
1579 macfont_encode_char,
1580 macfont_text_extents,
1581 macfont_draw,
1582 NULL, /* get_bitmap */
1583 NULL, /* free_bitmap */
1584 NULL, /* get_outline */
1585 NULL, /* free_outline */
1586 NULL, /* anchor_point */
1587 NULL, /* otf_capability */
1588 NULL, /* otf_drive */
1589 NULL, /* start_for_frame */
1590 NULL, /* end_for_frame */
1591 macfont_shape,
1592 NULL, /* check */
1593 macfont_variation_glyphs,
1594 macfont_filter_properties,
1595 };
1596
1597static Lisp_Object
1598macfont_get_cache (struct frame * f)
1599{
1600 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1601
1602 return (dpyinfo->name_list_element);
1603}
1604
1605static int
1606macfont_get_charset (Lisp_Object registry)
1607{
1608 char *str = SSDATA (SYMBOL_NAME (registry));
1609 char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1610 Lisp_Object regexp;
1611 int i, j;
1612
1613 for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1614 {
1615 if (str[i] == '.')
1616 re[j++] = '\\';
1617 else if (str[i] == '*')
1618 re[j++] = '.';
1619 re[j] = str[i];
1620 if (re[j] == '?')
1621 re[j] = '.';
1622 }
1623 re[j] = '\0';
1624 regexp = make_unibyte_string (re, j);
1625 for (i = 0; cf_charset_table[i].name; i++)
1626 if (fast_c_string_match_ignore_case
1627 (regexp, cf_charset_table[i].name,
1628 strlen (cf_charset_table[i].name)) >= 0)
1629 break;
1630 if (! cf_charset_table[i].name)
1631 return -1;
1632 if (! cf_charset_table[i].cf_charset)
1633 {
1634 int *uniquifier = cf_charset_table[i].uniquifier;
1635 UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1636 CFIndex count = 0;
1637 CFStringRef string;
1638 CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1639
1640 if (! charset)
1641 return -1;
1642 for (j = 0; uniquifier[j]; j++)
1643 {
1644 count += macfont_store_utf32char_to_unichars (uniquifier[j],
1645 unichars + count);
1646 CFCharacterSetAddCharactersInRange (charset,
1647 CFRangeMake (uniquifier[j], 1));
1648 }
1649
1650 string = CFStringCreateWithCharacters (NULL, unichars, count);
1651 if (! string)
1652 {
1653 CFRelease (charset);
1654 return -1;
1655 }
1656 cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1657 charset);
1658 CFRelease (charset);
1659 /* CFCharacterSetCreateWithCharactersInString does not handle
1660 surrogate pairs properly as of Mac OS X 10.5. */
1661 cf_charset_table[i].cf_charset_string = string;
1662 }
1663 return i;
1664}
1665
1666struct OpenTypeSpec
1667{
1668 Lisp_Object script;
1669 unsigned int script_tag, langsys_tag;
1670 int nfeatures[2];
1671 unsigned int *features[2];
1672};
1673
1674#define OTF_SYM_TAG(SYM, TAG) \
1675 do { \
1676 unsigned char *p = SDATA (SYMBOL_NAME (SYM)); \
1677 TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \
1678 } while (0)
1679
1680#define OTF_TAG_STR(TAG, P) \
1681 do { \
1682 (P)[0] = (char) (TAG >> 24); \
1683 (P)[1] = (char) ((TAG >> 16) & 0xFF); \
1684 (P)[2] = (char) ((TAG >> 8) & 0xFF); \
1685 (P)[3] = (char) (TAG & 0xFF); \
1686 (P)[4] = '\0'; \
1687 } while (0)
1688
1689static struct OpenTypeSpec *
1690macfont_get_open_type_spec (Lisp_Object otf_spec)
1691{
1692 struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1693 Lisp_Object val;
1694 int i, j;
1695 bool negative;
1696
1697 if (! spec)
1698 return NULL;
1699 spec->script = XCAR (otf_spec);
1700 if (! NILP (spec->script))
1701 {
1702 OTF_SYM_TAG (spec->script, spec->script_tag);
1703 val = assq_no_quit (spec->script, Votf_script_alist);
1704 if (CONSP (val) && SYMBOLP (XCDR (val)))
1705 spec->script = XCDR (val);
1706 else
1707 spec->script = Qnil;
1708 }
1709 else
1710 spec->script_tag = 0x44464C54; /* "DFLT" */
1711 otf_spec = XCDR (otf_spec);
1712 spec->langsys_tag = 0;
1713 if (! NILP (otf_spec))
1714 {
1715 val = XCAR (otf_spec);
1716 if (! NILP (val))
1717 OTF_SYM_TAG (val, spec->langsys_tag);
1718 otf_spec = XCDR (otf_spec);
1719 }
1720 spec->nfeatures[0] = spec->nfeatures[1] = 0;
1721 for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1722 {
1723 Lisp_Object len;
1724
1725 val = XCAR (otf_spec);
1726 if (NILP (val))
1727 continue;
1728 len = Flength (val);
1729 spec->features[i] =
1730 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1731 ? 0
1732 : malloc (XINT (len) * sizeof *spec->features[i]));
1733 if (! spec->features[i])
1734 {
1735 if (i > 0 && spec->features[0])
1736 free (spec->features[0]);
1737 free (spec);
1738 return NULL;
1739 }
1740 for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1741 {
1742 if (NILP (XCAR (val)))
1743 negative = 1;
1744 else
1745 {
1746 unsigned int tag;
1747
1748 OTF_SYM_TAG (XCAR (val), tag);
1749 spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1750 }
1751 }
1752 spec->nfeatures[i] = j;
1753 }
1754 return spec;
1755}
1756
1757static CFMutableDictionaryRef
1758macfont_create_attributes_with_spec (Lisp_Object spec)
1759{
1760 Lisp_Object tmp, extra;
1761 CFMutableArrayRef langarray = NULL;
1762 CFCharacterSetRef charset = NULL;
1763 CFStringRef charset_string = NULL;
1764 CFMutableDictionaryRef attributes = NULL, traits = NULL;
1765 Lisp_Object script = Qnil;
1766 Lisp_Object registry;
1767 int cf_charset_idx, i;
1768 struct OpenTypeSpec *otspec = NULL;
1769 struct {
1770 enum font_property_index index;
1771 CFStringRef trait;
1772 CGPoint points[6];
1773 } numeric_traits[] =
1774 {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1775 {{-0.4, 50}, /* light */
1776 {-0.24, 87.5}, /* (semi-light + normal) / 2 */
1777 {0, 100}, /* normal */
1778 {0.24, 140}, /* (semi-bold + normal) / 2 */
1779 {0.4, 200}, /* bold */
1780 {CGFLOAT_MAX, CGFLOAT_MAX}}},
1781 {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1782 {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1783 {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1784 {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1785
1786 registry = AREF (spec, FONT_REGISTRY_INDEX);
1787 if (NILP (registry)
1788 || EQ (registry, Qascii_0)
1789 || EQ (registry, Qiso10646_1)
1790 || EQ (registry, Qunicode_bmp))
1791 cf_charset_idx = -1;
1792 else
1793 {
1794 CFStringRef lang;
1795
1796 cf_charset_idx = macfont_get_charset (registry);
1797 if (cf_charset_idx < 0)
1798 goto err;
1799 charset = cf_charset_table[cf_charset_idx].cf_charset;
1800 charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1801 lang = cf_charset_table[cf_charset_idx].lang;
1802 if (lang)
1803 {
1804 langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1805 if (! langarray)
1806 goto err;
1807 CFArrayAppendValue (langarray, lang);
1808 }
1809 }
1810
1811 for (extra = AREF (spec, FONT_EXTRA_INDEX);
1812 CONSP (extra); extra = XCDR (extra))
1813 {
1814 Lisp_Object key, val;
1815
1816 tmp = XCAR (extra);
1817 key = XCAR (tmp), val = XCDR (tmp);
1818 if (EQ (key, QClang))
1819 {
1820 if (! langarray)
1821 langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1822 if (! langarray)
1823 goto err;
1824 if (SYMBOLP (val))
1825 val = list1 (val);
1826 for (; CONSP (val); val = XCDR (val))
1827 if (SYMBOLP (XCAR (val)))
1828 {
1829 CFStringRef lang =
1830 cfstring_create_with_string_noencode (SYMBOL_NAME
1831 (XCAR (val)));
1832
1833 if (lang == NULL)
1834 goto err;
1835 CFArrayAppendValue (langarray, lang);
1836 CFRelease (lang);
1837 }
1838 }
1839 else if (EQ (key, QCotf))
1840 {
1841 otspec = macfont_get_open_type_spec (val);
1842 if (! otspec)
1843 goto err;
1844 script = otspec->script;
1845 }
1846 else if (EQ (key, QCscript))
1847 script = val;
1848 }
1849
1850 if (! NILP (script) && ! charset)
1851 {
1852 Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1853
1854 if (CONSP (chars) && CONSP (CDR (chars)))
1855 {
1856 CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1857 CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1858
1859 if (! string || !cs)
1860 {
1861 if (string)
1862 CFRelease (string);
1863 else if (cs)
1864 CFRelease (cs);
1865 goto err;
1866 }
1867 for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1868 if (CHARACTERP (XCAR (chars)))
1869 {
1870 UniChar unichars[2];
1871 CFIndex count =
1872 macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1873 unichars);
1874 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1875
1876 CFStringAppendCharacters (string, unichars, count);
1877 CFCharacterSetAddCharactersInRange (cs, range);
1878 }
1879 charset = cs;
1880 /* CFCharacterSetCreateWithCharactersInString does not
1881 handle surrogate pairs properly as of Mac OS X 10.5. */
1882 charset_string = string;
1883 }
1884 }
1885
1886 attributes = CFDictionaryCreateMutable (NULL, 0,
1887 &kCFTypeDictionaryKeyCallBacks,
1888 &kCFTypeDictionaryValueCallBacks);
1889 if (! attributes)
1890 goto err;
1891
1892 tmp = AREF (spec, FONT_FAMILY_INDEX);
1893 if (SYMBOLP (tmp) && ! NILP (tmp))
1894 {
1895 CFStringRef family = macfont_create_family_with_symbol (tmp);
1896
1897 if (! family)
1898 goto err;
1899 CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1900 family);
1901 CFRelease (family);
1902 }
1903
1904 traits = CFDictionaryCreateMutable (NULL, 4,
1905 &kCFTypeDictionaryKeyCallBacks,
1906 &kCFTypeDictionaryValueCallBacks);
1907 if (! traits)
1908 goto err;
1909
705cf384 1910 for (i = 0; i < EARRAYSIZE (numeric_traits); i++)
d93ab42e
JD
1911 {
1912 tmp = AREF (spec, numeric_traits[i].index);
1913 if (INTEGERP (tmp))
1914 {
1915 CGPoint *point = numeric_traits[i].points;
1916 CGFloat floatval = (XINT (tmp) >> 8); // XXX
1917 CFNumberRef num;
1918
1919 while (point->y < floatval)
1920 point++;
1921 if (point == numeric_traits[i].points)
1922 point++;
1923 else if (point->y == CGFLOAT_MAX)
1924 point--;
1925 floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1926 * ((point->x - (point - 1)->x)
1927 / (point->y - (point - 1)->y)));
1928 if (floatval > 1.0)
1929 floatval = 1.0;
1930 else if (floatval < -1.0)
1931 floatval = -1.0;
1932 num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1933 if (! num)
1934 goto err;
1935 CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1936 CFRelease (num);
1937 }
1938 }
1939 if (CFDictionaryGetCount (traits))
1940 CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1941
1942 if (charset)
1943 CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1944 charset);
1945 if (charset_string)
1946 CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1947 charset_string);
1948 if (langarray)
1949 CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1950
1951 goto finish;
1952
1953 err:
1954 if (attributes)
1955 {
1956 CFRelease (attributes);
1957 attributes = NULL;
1958 }
1959
1960 finish:
1961 if (langarray) CFRelease (langarray);
1962 if (charset && cf_charset_idx < 0) CFRelease (charset);
1963 if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1964 if (traits) CFRelease (traits);
1965 if (otspec)
1966 {
1967 if (otspec->nfeatures[0] > 0)
1968 free (otspec->features[0]);
1969 if (otspec->nfeatures[1] > 0)
1970 free (otspec->features[1]);
1971 free (otspec);
1972 }
1973
1974 return attributes;
1975}
1976
1977static Boolean
1978macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1979 CFCharacterSetRef charset,
1980 Lisp_Object chars,
1981 CFArrayRef languages)
1982{
1983 Boolean result = true;
1984
1985 if (charset || VECTORP (chars))
1986 {
1987 CFCharacterSetRef desc_charset =
1988 mac_font_descriptor_copy_attribute (desc,
1989 MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1990
1991 if (desc_charset == NULL)
1992 result = false;
1993 else
1994 {
1995 if (charset)
1996 result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1997 else /* VECTORP (chars) */
1998 {
1999 ptrdiff_t j;
2000
2001 for (j = 0; j < ASIZE (chars); j++)
2002 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2003 && CFCharacterSetIsLongCharacterMember (desc_charset,
2004 XFASTINT (AREF (chars, j))))
2005 break;
2006 if (j == ASIZE (chars))
2007 result = false;
2008 }
2009 CFRelease (desc_charset);
2010 }
2011 }
2012 if (result && languages)
2013 result = mac_font_descriptor_supports_languages (desc, languages);
2014
2015 return result;
2016}
2017
2018static CFIndex
2019macfont_closest_traits_index (CFArrayRef traits_array,
2020 FontSymbolicTraits target)
2021{
2022 CFIndex i, result = -1, count = CFArrayGetCount (traits_array);
2023 int min_distance = (1 << 3);
2024
2025 for (i = 0; i < count; i++)
2026 {
2027 FontSymbolicTraits traits, diff;
2028 int distance = 0;
2029
2030 traits = ((FontSymbolicTraits) (uintptr_t)
2031 CFArrayGetValueAtIndex (traits_array, i));
2032 diff = (target ^ traits);
2033 /* We prefer synthetic bold of italic to synthetic italic of
2034 bold when both bold and italic are available but bold-italic
2035 is not available. */
2036 if (diff & MAC_FONT_TRAIT_BOLD)
2037 distance |= (1 << 0);
2038 if (diff & MAC_FONT_TRAIT_ITALIC)
2039 distance |= (1 << 1);
2040 if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2041 distance |= (1 << 2);
2042 if (distance < min_distance)
2043 {
2044 min_distance = distance;
2045 result = i;
2046 }
2047 }
2048
2049 return result;
2050}
2051
2052static Lisp_Object
2053macfont_list (struct frame *f, Lisp_Object spec)
2054{
2055 Lisp_Object val = Qnil, family, extra;
2056 int i, n;
2057 CFStringRef family_name = NULL;
2058 CFMutableDictionaryRef attributes = NULL, traits;
2059 Lisp_Object chars = Qnil;
2060 int spacing = -1;
2061 FontSymbolicTraits synth_sym_traits = 0;
2062 CFArrayRef families;
2063 CFIndex families_count;
2064 CFCharacterSetRef charset = NULL;
2065 CFArrayRef languages = NULL;
2066
2067 block_input ();
2068
2069 family = AREF (spec, FONT_FAMILY_INDEX);
2070 if (! NILP (family))
2071 {
2072 family_name = macfont_create_family_with_symbol (family);
2073 if (family_name == NULL)
2074 goto finish;
2075 }
2076
2077 attributes = macfont_create_attributes_with_spec (spec);
2078 if (! attributes)
2079 goto finish;
2080
5ee29210 2081 languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
d93ab42e
JD
2082
2083 if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2084 spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2085
2086 traits = ((CFMutableDictionaryRef)
2087 CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2088
2089 n = FONT_SLANT_NUMERIC (spec);
2090 if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2091 {
2092 synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2093 if (traits)
2094 CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2095 }
2096
2097 n = FONT_WEIGHT_NUMERIC (spec);
2098 if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2099 {
2100 synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2101 if (traits)
2102 CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2103 }
2104
2105 if (languages
2106 && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2107 {
2108 CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2109
2110 if (CFStringHasPrefix (language, CFSTR ("ja"))
2111 || CFStringHasPrefix (language, CFSTR ("ko"))
2112 || CFStringHasPrefix (language, CFSTR ("zh")))
2113 synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2114 }
2115
2116 /* Create array of families. */
2117 if (family_name)
2118 families = CFArrayCreate (NULL, (const void **) &family_name,
2119 1, &kCFTypeArrayCallBacks);
2120 else
2121 {
2122 CFStringRef pref_family;
2123 CFIndex families_count, pref_family_index = -1;
2124
2125 families = mac_font_create_available_families ();
2126 if (families == NULL)
2127 goto err;
2128
2129 families_count = CFArrayGetCount (families);
2130
2131 /* Move preferred family to the front if exists. */
2132 pref_family =
2133 mac_font_create_preferred_family_for_attributes (attributes);
2134 if (pref_family)
2135 {
2136 pref_family_index =
2137 CFArrayGetFirstIndexOfValue (families,
2138 CFRangeMake (0, families_count),
2139 pref_family);
2140 CFRelease (pref_family);
2141 }
2142 if (pref_family_index > 0)
2143 {
2144 CFMutableArrayRef mutable_families =
2145 CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2146
2147 if (mutable_families)
2148 {
2149 CFArrayAppendValue (mutable_families,
2150 CFArrayGetValueAtIndex (families,
2151 pref_family_index));
2152 CFArrayAppendArray (mutable_families, families,
2153 CFRangeMake (0, pref_family_index));
2154 if (pref_family_index + 1 < families_count)
2155 CFArrayAppendArray (mutable_families, families,
2156 CFRangeMake (pref_family_index + 1,
2157 families_count
2158 - (pref_family_index + 1)));
2159 CFRelease (families);
2160 families = mutable_families;
2161 }
2162 }
2163 }
2164
5ee29210
JD
2165 charset = CFDictionaryGetValue (attributes,
2166 MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2167 if (charset)
2168 {
2169 CFRetain (charset);
2170 CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2171 }
2172 else
2173 {
2174 val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2175 if (! NILP (val))
2176 {
2177 val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2178 if (CONSP (val) && VECTORP (XCDR (val)))
2179 chars = XCDR (val);
2180 }
2181 val = Qnil;
2182 }
2183
2184 if (languages)
2185 {
2186 CFRetain (languages);
2187 CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2188 }
2189
d93ab42e
JD
2190 val = Qnil;
2191 extra = AREF (spec, FONT_EXTRA_INDEX);
2192 families_count = CFArrayGetCount (families);
2193 for (i = 0; i < families_count; i++)
2194 {
2195 CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2196 FontDescriptorRef pat_desc;
2197 CFArrayRef descs;
2198 CFIndex descs_count;
2199 CFMutableArrayRef filtered_descs, traits_array;
2200 Lisp_Object entity;
2201 int j;
2202
2203 CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2204 family_name);
2205 pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2206 if (! pat_desc)
2207 goto err;
2208
2209 /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2210 10.7 returns NULL if pat_desc represents the LastResort font.
2211 So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2212 trailing "s") for such a font. */
2213 if (CFStringCompare (family_name, CFSTR ("LastResort"), 0)
2214 != kCFCompareEqualTo)
2215 descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2216 NULL);
2217 else
2218 {
2219 FontDescriptorRef lr_desc =
2220 mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2221 NULL);
2222 if (lr_desc)
2223 {
2224 descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2225 &kCFTypeArrayCallBacks);
2226 CFRelease (lr_desc);
2227 }
2228 else
2229 descs = NULL;
2230 }
2231 CFRelease (pat_desc);
2232 if (! descs)
2233 goto err;
2234
2235 descs_count = CFArrayGetCount (descs);
2236 if (descs_count == 0
2237 || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2238 charset, chars,
2239 languages))
2240 {
2241 CFRelease (descs);
2242 continue;
2243 }
2244
2245 filtered_descs =
2246 CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2247 traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2248 for (j = 0; j < descs_count; j++)
2249 {
2250 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2251 CFDictionaryRef dict;
2252 CFNumberRef num;
2253 FontSymbolicTraits sym_traits;
2254
2255 dict = mac_font_descriptor_copy_attribute (desc,
2256 MAC_FONT_TRAITS_ATTRIBUTE);
2257 if (dict == NULL)
2258 continue;
2259
2260 num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2261 CFRelease (dict);
2262 if (num == NULL
2263 || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2264 continue;
2265
2266 if (spacing >= 0
2267 && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2268 && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2269 != (spacing >= FONT_SPACING_MONO)))
2270 continue;
2271
2272 /* Don't use a color bitmap font unless its family is
2273 explicitly specified. */
2274 if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2275 continue;
2276
2277 if (j > 0
2278 && !macfont_supports_charset_and_languages_p (desc, charset,
2279 chars, languages))
2280 continue;
2281
2282 CFArrayAppendValue (filtered_descs, desc);
2283 CFArrayAppendValue (traits_array,
2284 (const void *) (uintptr_t) sym_traits);
2285 }
2286
2287 CFRelease (descs);
2288 descs = filtered_descs;
2289 descs_count = CFArrayGetCount (descs);
2290
2291 for (j = 0; j < descs_count; j++)
2292 {
2293 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2294 FontSymbolicTraits sym_traits =
2295 ((FontSymbolicTraits) (uintptr_t)
2296 CFArrayGetValueAtIndex (traits_array, j));
2297 FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2298
2299 mask_min = ((synth_sym_traits ^ sym_traits)
2300 & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2301 if (FONT_SLANT_NUMERIC (spec) < 0)
2302 mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2303 if (FONT_WEIGHT_NUMERIC (spec) < 0)
2304 mask_min &= ~MAC_FONT_TRAIT_BOLD;
2305
2306 mask_max = (synth_sym_traits & ~sym_traits);
2307 /* Synthetic bold does not work for bitmap-only fonts on Mac
2308 OS X 10.6. */
2309 if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2310 {
2311 CFNumberRef format =
2312 mac_font_descriptor_copy_attribute (desc,
2313 MAC_FONT_FORMAT_ATTRIBUTE);
2314
2315 if (format)
2316 {
2317 uint32_t format_val;
2318
2319 if (CFNumberGetValue (format, kCFNumberSInt32Type,
2320 &format_val)
2321 && format_val == MAC_FONT_FORMAT_BITMAP)
2322 mask_max &= ~MAC_FONT_TRAIT_BOLD;
2323 }
2324 }
2325 if (spacing >= 0)
2326 mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2327
2328 for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2329 mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2330 mmask += MAC_FONT_TRAIT_MONO_SPACE)
2331 for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2332 bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2333 bmask += MAC_FONT_TRAIT_BOLD)
2334 for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2335 imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2336 imask += MAC_FONT_TRAIT_ITALIC)
2337 {
2338 FontSymbolicTraits synth = (imask | bmask | mmask);
2339
2340 if (synth == 0
2341 || j == macfont_closest_traits_index (traits_array,
2342 (sym_traits | synth)))
2343 {
2344 entity = macfont_descriptor_entity (desc, extra, synth);
2345 if (! NILP (entity))
2346 val = Fcons (entity, val);
2347 }
2348 }
2349 }
2350
2351 CFRelease (traits_array);
2352 CFRelease (descs);
2353 }
2354
2355 CFRelease (families);
2356 val = Fnreverse (val);
2357 goto finish;
2358 err:
2359 val = Qnil;
2360
2361 finish:
2362 FONT_ADD_LOG ("macfont-list", spec, val);
2363 if (charset) CFRelease (charset);
2364 if (languages) CFRelease (languages);
2365 if (attributes) CFRelease (attributes);
2366 if (family_name) CFRelease (family_name);
2367
2368 unblock_input ();
2369
2370 return val;
2371}
2372
2373static Lisp_Object
2374macfont_match (struct frame * frame, Lisp_Object spec)
2375{
2376 Lisp_Object entity = Qnil;
2377 CFMutableDictionaryRef attributes;
2378 FontDescriptorRef pat_desc = NULL, desc = NULL;
2379
2380 block_input ();
2381
2382 attributes = macfont_create_attributes_with_spec (spec);
2383 if (attributes)
2384 {
2385 pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2386 CFRelease (attributes);
2387 }
2388 if (pat_desc)
2389 {
2390 desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2391 NULL);
2392 CFRelease (pat_desc);
2393 }
2394 if (desc)
2395 {
2396 entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2397 0);
2398 CFRelease (desc);
2399 }
2400 unblock_input ();
2401
2402 FONT_ADD_LOG ("macfont-match", spec, entity);
2403 return entity;
2404}
2405
2406static Lisp_Object
2407macfont_list_family (struct frame *frame)
2408{
2409 Lisp_Object list = Qnil;
2410 CFArrayRef families;
2411
2412 block_input ();
2413
2414 families = mac_font_create_available_families ();
2415 if (families)
2416 {
2417 CFIndex i, count = CFArrayGetCount (families);
2418
2419 for (i = 0; i < count; i++)
2420 list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2421 CFRelease (families);
2422 }
2423
2424 unblock_input ();
2425
2426 return list;
2427}
2428
2429static void
2430macfont_free_entity (Lisp_Object entity)
2431{
2432 Lisp_Object val = assq_no_quit (QCfont_entity,
2433 AREF (entity, FONT_EXTRA_INDEX));
2434 CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2435
2436 block_input ();
2437 CFRelease (name);
2438 unblock_input ();
2439}
2440
2441static Lisp_Object
2442macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2443{
2444 Lisp_Object val, font_object;
2445 CFStringRef font_name;
2446 struct macfont_info *macfont_info = NULL;
2447 struct font *font;
2448 int size;
2449 FontRef macfont;
2450 FontSymbolicTraits sym_traits;
2451 char name[256];
2452 int len, i, total_width;
2453 CGGlyph glyph;
2454 CGFloat ascent, descent, leading;
2455
2456 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2457 if (! CONSP (val)
2458 || XTYPE (XCDR (val)) != Lisp_Misc
2459 || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2460 return Qnil;
2461 font_name = XSAVE_POINTER (XCDR (val), 0);
2462 sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2463
2464 size = XINT (AREF (entity, FONT_SIZE_INDEX));
2465 if (size == 0)
2466 size = pixel_size;
2467
2468 block_input ();
2469 macfont = mac_font_create_with_name (font_name, size);
2470 if (macfont)
2471 {
2472 int fontsize = (int) [((NSFont *) macfont) pointSize];
2473 if (fontsize != size) size = fontsize;
2474 }
2475 unblock_input ();
2476 if (! macfont)
2477 return Qnil;
2478
2479 font_object = font_make_object (VECSIZE (struct macfont_info), entity, size);
2480 ASET (font_object, FONT_TYPE_INDEX, macfont_driver.type);
2481 len = font_unparse_xlfd (entity, size, name, 256);
2482 if (len > 0)
2483 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
2484 len = font_unparse_fcname (entity, size, name, 256);
2485 if (len > 0)
2486 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
2487 else
2488 ASET (font_object, FONT_FULLNAME_INDEX,
2489 AREF (font_object, FONT_NAME_INDEX));
2490 font = XFONT_OBJECT (font_object);
2491 font->pixel_size = size;
2492 font->driver = &macfont_driver;
2493 font->encoding_charset = font->repertory_charset = -1;
2494
2495 block_input ();
2496
2497 macfont_info = (struct macfont_info *) font;
2498 macfont_info->macfont = macfont;
2499 macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
a67c4ae0 2500
d93ab42e
JD
2501 val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2502 if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2503 macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2504 size);
2505 else
2506 macfont_info->screen_font = NULL;
2507 macfont_info->cache = macfont_lookup_cache (font_name);
2508 macfont_retain_cache (macfont_info->cache);
2509 macfont_info->metrics = NULL;
2510 macfont_info->metrics_nrows = 0;
2511 macfont_info->synthetic_italic_p = 0;
2512 macfont_info->synthetic_bold_p = 0;
2513 macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2514 macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2515 if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2516 && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2517 macfont_info->synthetic_italic_p = 1;
2518 if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2519 && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2520 macfont_info->synthetic_bold_p = 1;
2521 if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2522 macfont_info->spacing = MACFONT_SPACING_MONO;
2523 else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2524 && (XINT (AREF (entity, FONT_SPACING_INDEX))
2525 == FONT_SPACING_SYNTHETIC_MONO))
2526 macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2527 if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2528 macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2529 else
2530 {
2531 val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2532 if (CONSP (val))
2533 macfont_info->antialias =
2534 NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2535 }
2536 macfont_info->color_bitmap_p = 0;
2537 if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2538 macfont_info->color_bitmap_p = 1;
2539
2540 glyph = macfont_get_glyph_for_character (font, ' ');
2541 if (glyph != kCGFontIndexInvalid)
2542 font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2543 else
2544 /* dirty workaround */
2545 font->space_width = pixel_size;
2546
2547 total_width = font->space_width;
2548 for (i = 1; i < 95; i++)
2549 {
2550 glyph = macfont_get_glyph_for_character (font, ' ' + i);
2551 if (glyph == kCGFontIndexInvalid)
2552 break;
2553 total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2554 }
2555 if (i == 95)
2556 font->average_width = total_width / 95;
2557 else
2558 font->average_width = font->space_width; /* XXX */
2559
2560 if (!(macfont_info->screen_font
2561 && mac_screen_font_get_metrics (macfont_info->screen_font,
2562 &ascent, &descent, &leading)))
2563 {
2564 CFStringRef family_name;
2565
2566 ascent = mac_font_get_ascent (macfont);
2567 descent = mac_font_get_descent (macfont);
2568 leading = mac_font_get_leading (macfont);
2569 /* AppKit and WebKit do some adjustment to the heights of
2570 Courier, Helvetica, and Times. */
2571 family_name = mac_font_copy_family_name (macfont);
2572 if (family_name)
2573 {
2574 if ((CFStringCompare (family_name, CFSTR ("Courier"), 0)
2575 == kCFCompareEqualTo)
2576 || (CFStringCompare (family_name, CFSTR ("Helvetica"), 0)
2577 == kCFCompareEqualTo)
2578 || (CFStringCompare (family_name, CFSTR ("Times"), 0)
2579 == kCFCompareEqualTo))
2580 ascent += (ascent + descent) * .15f;
2581 else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2582 {
2583 leading *= .25f;
2584 ascent += leading;
2585 }
2586 CFRelease (family_name);
2587 }
2588 }
2589 font->ascent = ascent + 0.5f;
2590 val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2591 if (CONSP (val) && !NILP (XCDR (val)))
2592 font->descent = descent + 0.5f;
2593 else
2594 font->descent = descent + leading + 0.5f;
2595 font->height = font->ascent + font->descent;
2596
2597 font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2598 font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2599
2600 unblock_input ();
2601
2602 /* Unfortunately Xft doesn't provide a way to get minimum char
2603 width. So, we use space_width instead. */
2604 font->min_width = font->max_width = font->space_width; /* XXX */
2605
2606 font->baseline_offset = 0;
2607 font->relative_compose = 0;
2608 font->default_ascent = 0;
2609 font->vertical_centering = 0;
2610
2611 return font_object;
2612}
2613
2614static void
78e0b35c 2615macfont_close (struct font *font)
d93ab42e
JD
2616{
2617 struct macfont_info *macfont_info = (struct macfont_info *) font;
5ee29210 2618 int i;
d93ab42e 2619
5ee29210
JD
2620 block_input ();
2621 CFRelease (macfont_info->macfont);
2622 CGFontRelease (macfont_info->cgfont);
2623 if (macfont_info->screen_font)
2624 CFRelease (macfont_info->screen_font);
2625 macfont_release_cache (macfont_info->cache);
2626 for (i = 0; i < macfont_info->metrics_nrows; i++)
2627 if (macfont_info->metrics[i])
2628 xfree (macfont_info->metrics[i]);
2629 if (macfont_info->metrics)
2630 xfree (macfont_info->metrics);
2631 unblock_input ();
d93ab42e
JD
2632}
2633
2634static int
2635macfont_has_char (Lisp_Object font, int c)
2636{
2637 int result;
2638 CFCharacterSetRef charset;
2639
2640 block_input ();
2641 if (FONT_ENTITY_P (font))
2642 {
2643 Lisp_Object val;
2644 CFStringRef name;
2645
2646 val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2647 val = XCDR (val);
2648 name = XSAVE_POINTER (val, 0);
2649 charset = macfont_get_cf_charset_for_name (name);
2650 }
2651 else
2652 charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2653
2654 result = CFCharacterSetIsLongCharacterMember (charset, c);
2655 unblock_input ();
2656
2657 return result;
2658}
2659
2660static unsigned
2661macfont_encode_char (struct font *font, int c)
2662{
2663 struct macfont_info *macfont_info = (struct macfont_info *) font;
2664 CGGlyph glyph;
2665
2666 block_input ();
2667 glyph = macfont_get_glyph_for_character (font, c);
2668 unblock_input ();
2669
2670 return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2671}
2672
2673static int
2674macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2675 struct font_metrics *metrics)
2676{
2677 int width, i;
2678
2679 block_input ();
2680 width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2681 for (i = 1; i < nglyphs; i++)
2682 {
2683 struct font_metrics m;
2684 int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2685 NULL, 0);
2686
2687 if (metrics)
2688 {
2689 if (width + m.lbearing < metrics->lbearing)
2690 metrics->lbearing = width + m.lbearing;
2691 if (width + m.rbearing > metrics->rbearing)
2692 metrics->rbearing = width + m.rbearing;
2693 if (m.ascent > metrics->ascent)
2694 metrics->ascent = m.ascent;
2695 if (m.descent > metrics->descent)
2696 metrics->descent = m.descent;
2697 }
2698 width += w;
2699 }
2700 unblock_input ();
2701
a67c4ae0 2702 if (metrics)
d93ab42e
JD
2703 metrics->width = width;
2704
2705 return width;
2706}
2707
2708static int
2709macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2710 bool with_background)
2711{
2712 struct frame * f = s->f;
2713 struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2714 FontRef macfont = macfont_info->macfont;
2715 CGContextRef context;
2716 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2717 int end = isComposite ? s->cmp_to : s->nchars;
2718 int len = end - s->cmp_from;
6c21e306 2719 struct face *face = s->face;
d93ab42e
JD
2720 int i;
2721
2722 block_input ();
2723
2724 context = [[NSGraphicsContext currentContext] graphicsPort];
2725 CGContextSaveGState (context);
2726
2727#if 0
2728 if (s->num_clips > 0)
2729 {
2730 CGRect clips[2];
2731
2732 for (i = 0; i < s->num_clips; i++)
2733 clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2734 s->clip[i].right - s->clip[i].left,
2735 s->clip[i].bottom - s->clip[i].top);
2736 CGContextClipToRects (context, clips, s->num_clips);
2737 }
2738#endif
2739
2740 if (with_background)
2741 {
6c21e306
JD
2742 if (s->hl == DRAW_MOUSE_FACE)
2743 {
2744 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2745 if (!face)
2746 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2747 }
2748
2749 CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
d93ab42e 2750 CGContextFillRect (context,
45435f08 2751 CGRectMake (x, y,
d93ab42e
JD
2752 s->width, FONT_HEIGHT (s->font)));
2753 }
2754
2755 if (macfont_info->cgfont)
2756 {
2757 CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2758 CGPoint *positions = alloca (sizeof (CGPoint) * len);
2759 CGFloat total_width = 0;
2760 CGFloat font_size = mac_font_get_size (macfont);
2761 CGAffineTransform atfm;
2762 CGFloat advance_delta = 0;
c348360a 2763 int y_draw = -s->ybase;
d93ab42e
JD
2764 int no_antialias_p =
2765 (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2766 || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2767 && font_size <= macfont_antialias_threshold));
2768
2769 for (i = 0; i < len; i++)
2770 {
2771 int width;
a67c4ae0 2772
d93ab42e
JD
2773 glyphs[i] = *(s->char2b + s->cmp_from + i);
2774 width = (s->padding_p ? 1
2775 : macfont_glyph_extents (s->font, glyphs[i],
2776 NULL, &advance_delta,
2777 no_antialias_p));
2778 positions[i].x = total_width + advance_delta;
2779 positions[i].y = 0;
2780 total_width += width;
2781 }
2782
2783 CGContextScaleCTM (context, 1, -1);
6c21e306 2784 CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
d93ab42e
JD
2785 if (macfont_info->synthetic_italic_p)
2786 atfm = synthetic_italic_atfm;
2787 else
2788 atfm = CGAffineTransformIdentity;
2789 if (macfont_info->synthetic_bold_p)
2790 {
2791 CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2792 CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
6c21e306 2793 CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
d93ab42e
JD
2794 }
2795 if (no_antialias_p)
2796 CGContextSetShouldAntialias (context, false);
2797
2798 CGContextSetTextMatrix (context, atfm);
2799 CGContextSetTextPosition (context, x, y_draw);
2800
2801#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2802 if (macfont_info->color_bitmap_p
2803#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2804 && CTFontDrawGlyphs != NULL
2805#endif
2806 )
2807 {
2808 if (len > 0)
2809 {
2810 CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2811 }
2812 }
2813 else
2814#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2815 {
2816 CGContextSetFont (context, macfont_info->cgfont);
2817 CGContextSetFontSize (context, font_size);
2818 CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2819 }
2820 }
2821
2822 CGContextRestoreGState (context);
2823
2824 unblock_input ();
2825
2826 return len;
2827}
2828
5ee29210 2829static Lisp_Object
d93ab42e
JD
2830macfont_shape (Lisp_Object lgstring)
2831{
2832 struct font *font;
2833 struct macfont_info *macfont_info;
2834 FontRef macfont;
2835 ptrdiff_t glyph_len, len, i, j;
2836 CFIndex nonbmp_len;
2837 UniChar *unichars;
2838 CFIndex *nonbmp_indices;
2839 CFStringRef string;
2840 CFIndex used = 0;
2841 struct mac_glyph_layout *glyph_layouts;
2842
2843 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2844 macfont_info = (struct macfont_info *) font;
2845 macfont = macfont_info->macfont;
2846
2847 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2848 nonbmp_len = 0;
2849 for (i = 0; i < glyph_len; i++)
2850 {
2851 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2852
2853 if (NILP (lglyph))
2854 break;
2855 if (LGLYPH_CHAR (lglyph) >= 0x10000)
2856 nonbmp_len++;
2857 }
2858
2859 len = i;
d93ab42e
JD
2860
2861 if (INT_MAX / 2 < len)
2862 memory_full (SIZE_MAX);
2863
2864 unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2865 nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2866 for (i = j = 0; i < len; i++)
2867 {
2868 UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2869
2870 if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2871 {
2872 nonbmp_indices[j] = i + j;
2873 j++;
2874 }
2875 }
2876 nonbmp_indices[j] = len + j; /* sentinel */
2877
2878 block_input ();
2879
2880 string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2881 kCFAllocatorNull);
2882 if (string)
2883 {
2884 glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2885 if (macfont_info->screen_font)
2886 used = mac_screen_font_shape (macfont_info->screen_font, string,
2887 glyph_layouts, glyph_len);
2888 else
2889 used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2890 CFRelease (string);
2891 }
2892
2893 unblock_input ();
2894
2895 if (used == 0)
2896 return Qnil;
2897
2898 block_input ();
2899
2900 for (i = 0; i < used; i++)
2901 {
2902 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2903 struct mac_glyph_layout *gl = glyph_layouts + i;
2904 EMACS_INT from, to;
2905 struct font_metrics metrics;
2906 int xoff, yoff, wadjust;
2907
2908 if (NILP (lglyph))
2909 {
2910 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2911 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2912 }
2913
2914 from = gl->comp_range.location;
2915 /* Convert UTF-16 index to UTF-32. */
2916 j = 0;
2917 while (nonbmp_indices[j] < from)
2918 j++;
2919 from -= j;
2920 LGLYPH_SET_FROM (lglyph, from);
2921
2922 to = gl->comp_range.location + gl->comp_range.length;
2923 /* Convert UTF-16 index to UTF-32. */
2924 while (nonbmp_indices[j] < to)
2925 j++;
2926 to -= j;
2927 LGLYPH_SET_TO (lglyph, to - 1);
2928
2929 /* LGLYPH_CHAR is used in `describe-char' for checking whether
2930 the composition is trivial. */
2931 {
2932 UTF32Char c;
2933
2934 if (unichars[gl->string_index] >= 0xD800
2935 && unichars[gl->string_index] < 0xDC00)
2936 c = (((unichars[gl->string_index] - 0xD800) << 10)
2937 + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2938 else
2939 c = unichars[gl->string_index];
2940 if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2941 c = 0;
2942 LGLYPH_SET_CHAR (lglyph, c);
2943 }
2944
2945 {
2946 unsigned long cc = gl->glyph_id;
2947 LGLYPH_SET_CODE (lglyph, cc);
2948 }
2949
2950 macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2951 LGLYPH_SET_WIDTH (lglyph, metrics.width);
2952 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2953 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2954 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2955 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2956
2957 xoff = lround (gl->advance_delta);
2958 yoff = lround (- gl->baseline_delta);
2959 wadjust = lround (gl->advance);
2960 if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2961 {
2962 Lisp_Object vec;
2963
2964 vec = Fmake_vector (make_number (3), Qnil);
2965 ASET (vec, 0, make_number (xoff));
2966 ASET (vec, 1, make_number (yoff));
2967 ASET (vec, 2, make_number (wadjust));
2968 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2969 }
2970 }
2971
2972 unblock_input ();
2973
2974 return make_number (used);
2975}
2976
2977/* Structures for the UVS subtable (format 14) in the cmap table. */
2978typedef UInt8 UINT24[3];
2979
2980#pragma pack(push, 1)
2981struct variation_selector_record
2982{
2983 UINT24 var_selector;
2984 UInt32 default_uvs_offset, non_default_uvs_offset;
2985};
2986struct uvs_table
2987{
2988 UInt16 format;
2989 UInt32 length, num_var_selector_records;
2990 struct variation_selector_record variation_selector_records[1];
2991};
2992#define SIZEOF_UVS_TABLE_HEADER \
2993 (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2994
2995struct unicode_value_range
2996{
2997 UINT24 start_unicode_value;
2998 UInt8 additional_count;
2999};
3000struct default_uvs_table {
3001 UInt32 num_unicode_value_ranges;
3002 struct unicode_value_range unicode_value_ranges[1];
3003};
3004#define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3005 (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3006
3007struct uvs_mapping
3008{
3009 UINT24 unicode_value;
3010 UInt16 glyph_id;
3011};
3012struct non_default_uvs_table
3013{
3014 UInt32 num_uvs_mappings;
3015 struct uvs_mapping uvs_mappings[1];
3016};
3017#define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3018 (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3019#pragma pack(pop)
3020
3021/* Read big endian values. The argument LVAL must be an lvalue. */
3022/* I suppose OSReadBigInt* takes care of unaligned data. At least, we
3023 can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3024 OSReadBigInt16(cdb, 7);" in a sample code by Apple. */
3025#define BUINT8_VALUE(lval) (*((UInt8 *) &(lval)))
3026#define BUINT16_VALUE(lval) OSReadBigInt16 (&(lval), 0)
3027/* Succeeding one byte should also be accessible. */
3028#define BUINT24_VALUE(lval) (OSReadBigInt32 (&(lval), 0) >> 8)
3029#define BUINT32_VALUE(lval) OSReadBigInt32 (&(lval), 0)
3030
3031/* Return UVS subtable for the specified FONT. If the subtable is not
a67c4ae0 3032 found or ill-formatted, then return NULL. */
d93ab42e
JD
3033
3034static CFDataRef
3035mac_font_copy_uvs_table (FontRef font)
3036{
3037 CFDataRef cmap_table, uvs_table = NULL;
3038
3039 cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3040 if (cmap_table)
3041 {
3042 sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3043 struct uvs_table *uvs;
3044 struct variation_selector_record *records;
3045 UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3046
3047#if __LP64__
3048 if (CFDataGetLength (cmap_table) > UINT32_MAX)
3049 goto finish;
3050#endif
3051
3052 cmap_len = CFDataGetLength (cmap_table);
3053 if (sizeof_sfntCMapHeader > cmap_len)
3054 goto finish;
3055
3056 ntables = BUINT16_VALUE (cmap->numTables);
3057 if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3058 / sizeof_sfntCMapEncoding))
3059 goto finish;
3060
3061 for (i = 0; i < ntables; i++)
3062 if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3063 == kFontUnicodePlatform)
3064 && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3065 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3066 {
3067 uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3068 break;
3069 }
3070 if (i == ntables
3071 || uvs_offset > cmap_len
3072 || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3073 goto finish;
3074
3075 uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3076 uvs_len = BUINT32_VALUE (uvs->length);
3077 if (uvs_len > cmap_len - uvs_offset
3078 || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3079 goto finish;
3080
3081 if (BUINT16_VALUE (uvs->format) != 14)
3082 goto finish;
3083
3084 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3085 if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3086 / sizeof (struct variation_selector_record)))
3087 goto finish;
3088
3089 records = uvs->variation_selector_records;
3090 for (i = 0; i < nrecords; i++)
3091 {
3092 UInt32 default_uvs_offset, non_default_uvs_offset;
3093
3094 default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3095 if (default_uvs_offset)
3096 {
3097 struct default_uvs_table *default_uvs;
3098 UInt32 nranges;
3099
3100 if (default_uvs_offset > uvs_len
3101 || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3102 > uvs_len - default_uvs_offset))
3103 goto finish;
3104
3105 default_uvs = ((struct default_uvs_table *)
3106 ((UInt8 *) uvs + default_uvs_offset));
3107 nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3108 if (nranges > ((uvs_len - default_uvs_offset
3109 - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3110 / sizeof (struct unicode_value_range)))
3111 goto finish;
3112 /* Now 2 * nranges can't overflow, so we can safely use
3113 `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3114 mac_font_get_glyphs_for_variants. */
3115 }
3116
3117 non_default_uvs_offset =
3118 BUINT32_VALUE (records[i].non_default_uvs_offset);
3119 if (non_default_uvs_offset)
3120 {
3121 struct non_default_uvs_table *non_default_uvs;
3122 UInt32 nmappings;
3123
3124 if (non_default_uvs_offset > uvs_len
3125 || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3126 > uvs_len - non_default_uvs_offset))
3127 goto finish;
3128
3129 non_default_uvs = ((struct non_default_uvs_table *)
3130 ((UInt8 *) uvs + non_default_uvs_offset));
3131 nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3132 if (nmappings > ((uvs_len - non_default_uvs_offset
3133 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3134 / sizeof (struct uvs_mapping)))
3135 goto finish;
3136 /* Now 2 * nmappings can't overflow, so we can safely
3137 use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3138 in mac_font_get_glyphs_for_variants. */
3139 }
3140 }
3141
3142 uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3143
3144 finish:
3145 CFRelease (cmap_table);
3146 }
3147
3148 return uvs_table;
3149}
3150
3151/* Find an entry in the given UVS subtable UVS_TABLE for a variation
3152 sequence consisting of the given base character C and each
3153 variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3154 result (explained below) into the corresponding GLYPHS[i]. If the
3155 entry is found in the Default UVS Table, then the result is 0. If
3156 the entry is found in the Non-Default UVS Table, then the result is
3157 the associated glyph ID. Otherwise, kCGFontIndexInvalid. The
3158 elements in SELECTORS must be sorted in strictly increasing
3159 order. */
3160
3161static void
3162mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3163 const UTF32Char selectors[], CGGlyph glyphs[],
3164 CFIndex count)
3165{
3166 struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3167 struct variation_selector_record *records = uvs->variation_selector_records;
3168 CFIndex i;
3169 UInt32 ir, nrecords;
3170#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3171 dispatch_queue_t queue =
3172 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3173 dispatch_group_t group = dispatch_group_create ();
3174#endif
3175
3176 nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3177 i = 0;
3178 ir = 0;
3179 while (i < count && ir < nrecords)
3180 {
3181 UInt32 default_uvs_offset, non_default_uvs_offset;
3182
3183 if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3184 {
3185 glyphs[i++] = kCGFontIndexInvalid;
3186 continue;
3187 }
3188 else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3189 {
3190 ir++;
3191 continue;
3192 }
3193
3194 /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3195 default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3196 non_default_uvs_offset =
3197 BUINT32_VALUE (records[ir].non_default_uvs_offset);
3198#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3199 dispatch_group_async (group, queue, ^{
3200#endif
3201 glyphs[i] = kCGFontIndexInvalid;
3202
3203 if (default_uvs_offset)
3204 {
3205 struct default_uvs_table *default_uvs =
3206 (struct default_uvs_table *) ((UInt8 *) uvs
3207 + default_uvs_offset);
3208 struct unicode_value_range *ranges =
3209 default_uvs->unicode_value_ranges;
3210 UInt32 lo, hi;
3211
3212 lo = 0;
3213 hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3214 while (lo < hi)
3215 {
3216 UInt32 mid = (lo + hi) / 2;
3217
3218 if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3219 hi = mid;
3220 else
3221 lo = mid + 1;
3222 }
3223 if (hi > 0
3224 && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3225 + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3226 glyphs[i] = 0;
3227 }
3228
3229 if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3230 {
3231 struct non_default_uvs_table *non_default_uvs =
3232 (struct non_default_uvs_table *) ((UInt8 *) uvs
3233 + non_default_uvs_offset);
3234 struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3235 UInt32 lo, hi;
3236
3237 lo = 0;
3238 hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3239 while (lo < hi)
3240 {
3241 UInt32 mid = (lo + hi) / 2;
3242
3243 if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3244 hi = mid;
3245 else
3246 lo = mid + 1;
3247 }
3248 if (hi > 0 &&
3249 BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3250 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3251 }
3252#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3253 });
3254#endif
3255 i++;
3256 ir++;
3257 }
3258 while (i < count)
3259 glyphs[i++] = kCGFontIndexInvalid;
3260#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3261 dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3262 dispatch_release (group);
3263#endif
3264}
3265
3266static int
3267macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3268{
3269 CFDataRef uvs_table;
3270 CharacterCollection uvs_collection;
3271 int i, n = 0;
3272
3273 block_input ();
3274 uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3275
3276 if (uvs_table)
3277 {
3278 UTF32Char selectors[256];
3279 CGGlyph glyphs[256];
3280
3281 for (i = 0; i < 16; i++)
3282 selectors[i] = 0xFE00 + i;
3283 for (; i < 256; i++)
3284 selectors[i] = 0xE0100 + (i - 16);
3285 mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3286 for (i = 0; i < 256; i++)
3287 {
3288 CGGlyph glyph = glyphs[i];
3289
3290 if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3291 && glyph != kCGFontIndexInvalid)
3292 glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3293 if (glyph == kCGFontIndexInvalid)
3294 variations[i] = 0;
3295 else
3296 {
3297 variations[i] = (glyph ? glyph
3298 : macfont_get_glyph_for_character (font, c));
3299 n++;
3300 }
3301 }
3302 }
3303 unblock_input ();
3304
3305 return n;
3306}
3307
3308static const char *const macfont_booleans[] = {
3309 ":antialias",
3310 ":minspace",
3311 NULL,
3312};
3313
3314static const char *const macfont_non_booleans[] = {
3315 ":lang",
3316 ":script",
3317 ":destination",
3318 NULL,
3319};
3320
3321static void
3322macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3323{
3324 font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3325}
3326
3327static Boolean
3328mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3329 CFArrayRef languages)
3330{
3331 Boolean result = true;
3332 CFArrayRef desc_languages =
3333 CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3334
3335 if (desc_languages == NULL)
3336 result = false;
3337 else
3338 {
3339 CFIndex desc_languages_count, i, languages_count;
3340
3341 desc_languages_count = CFArrayGetCount (desc_languages);
3342 languages_count = CFArrayGetCount (languages);
3343 for (i = 0; i < languages_count; i++)
3344 if (!CFArrayContainsValue (desc_languages,
3345 CFRangeMake (0, desc_languages_count),
3346 CFArrayGetValueAtIndex (languages, i)))
3347 {
3348 result = false;
3349 break;
3350 }
3351 CFRelease (desc_languages);
3352 }
3353
3354 return result;
3355}
3356
3357static CFStringRef
3358mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3359{
3360 CFStringRef result = NULL;
3361 CFStringRef charset_string =
3362 CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
d93ab42e 3363
c348360a 3364 if (charset_string && CFStringGetLength (charset_string) > 0)
d93ab42e 3365 {
5ee29210
JD
3366 CFStringRef keys[] = {
3367#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3368 kCTLanguageAttributeName
3369#else
3370 CFSTR ("NSLanguage")
3371#endif
3372 };
3373 CFTypeRef values[] = {NULL};
3374 CFIndex num_values = 0;
3375 CFArrayRef languages
3376 = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
d93ab42e 3377
5ee29210 3378 if (languages && CFArrayGetCount (languages) > 0)
d93ab42e 3379 {
5ee29210
JD
3380 if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3381 values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3382 else
3383 {
3384 CFCharacterSetRef charset =
3385 CFDictionaryGetValue (attributes,
3386 MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3387
3388 result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3389 }
d93ab42e 3390 }
5ee29210 3391 if (result == NULL)
d93ab42e 3392 {
5ee29210
JD
3393 CFAttributedStringRef attr_string = NULL;
3394 CTLineRef ctline = NULL;
3395 CFDictionaryRef attrs
3396 = CFDictionaryCreate (NULL, (const void **) keys,
3397 (const void **) values, num_values,
3398 &kCFTypeDictionaryKeyCallBacks,
3399 &kCFTypeDictionaryValueCallBacks);
3400
3401 if (attrs)
d93ab42e 3402 {
5ee29210
JD
3403 attr_string = CFAttributedStringCreate (NULL, charset_string,
3404 attrs);
3405 CFRelease (attrs);
3406 }
3407 if (attr_string)
3408 {
3409 ctline = CTLineCreateWithAttributedString (attr_string);
3410 CFRelease (attr_string);
3411 }
3412 if (ctline)
3413 {
3414 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3415 CFIndex i, nruns = CFArrayGetCount (runs);
3416 CTFontRef font;
d93ab42e 3417
5ee29210
JD
3418 for (i = 0; i < nruns; i++)
3419 {
3420 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3421 CFDictionaryRef attributes = CTRunGetAttributes (run);
3422 CTFontRef font_in_run;
3423
3424 if (attributes == NULL)
3425 break;
3426 font_in_run =
3427 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3428 if (font_in_run == NULL)
3429 break;
3430 if (i == 0)
3431 font = font_in_run;
3432 else if (!mac_ctfont_equal_in_postscript_name (font,
3433 font_in_run))
3434 break;
3435 }
3436 if (nruns > 0 && i == nruns)
3437 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3438 CFRelease (ctline);
d93ab42e 3439 }
d93ab42e
JD
3440 }
3441 }
3442
3443 return result;
3444}
3445
3446static inline double
3447mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3448{
3449 return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3450 &glyph, NULL, 1);
3451}
3452
3453static inline CGRect
3454mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3455{
3456 return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3457 &glyph, NULL, 1);
3458}
3459
3460static CFArrayRef
3461mac_ctfont_create_available_families (void)
3462{
3463 CFMutableArrayRef families = NULL;
3464
3465#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3466#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3467 if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3468#endif
3469 {
3470 CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3471
3472 if (orig_families)
3473 {
3474 CFIndex i, count = CFArrayGetCount (orig_families);
3475
3476 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3477 if (families)
3478 for (i = 0; i < count; i++)
3479 {
3480 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3481
3482 if (!CFStringHasPrefix (family, CFSTR ("."))
3483 && (CTFontManagerCompareFontFamilyNames (family,
3484 CFSTR ("LastResort"),
3485 NULL)
3486 != kCFCompareEqualTo))
3487 CFArrayAppendValue (families, family);
3488 }
3489 CFRelease (orig_families);
3490 }
3491 }
3492#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3493 else /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3494#endif
3495#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3496#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3497 {
3498 CTFontCollectionRef collection;
3499 CFArrayRef descs = NULL;
3500
3501 collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3502 if (collection)
3503 {
3504 descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3505 CFRelease (collection);
3506 }
3507 if (descs)
3508 {
3509 CFIndex i, count = CFArrayGetCount (descs);
3510
3511 families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3512 if (families)
3513 for (i = 0; i < count; i++)
3514 {
3515 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3516 CFStringRef name =
3517 mac_font_descriptor_copy_attribute (desc,
3518 MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3519
3520 if (name)
3521 {
3522 CFIndex p, limit = CFArrayGetCount (families);
3523
3524 p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3525 (const void *) name,
3526 mac_font_family_compare, NULL);
3527 if (p >= limit)
3528 CFArrayAppendValue (families, name);
3529 else if (mac_font_family_compare
3530 (CFArrayGetValueAtIndex (families, p),
3531 name, NULL) != kCFCompareEqualTo)
3532 CFArrayInsertValueAtIndex (families, p, name);
3533 CFRelease (name);
3534 }
3535 }
3536 CFRelease (descs);
3537 }
3538 }
3539#endif
3540
3541 return families;
3542}
3543
3544static Boolean
3545mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3546{
3547 Boolean result;
3548 CFStringRef name1, name2;
3549
3550 if (font1 == font2)
3551 return true;
3552
3553 result = false;
3554 name1 = CTFontCopyPostScriptName (font1);
3555 if (name1)
3556 {
3557 name2 = CTFontCopyPostScriptName (font2);
3558 if (name2)
3559 {
3560 result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3561 CFRelease (name2);
3562 }
3563 CFRelease (name1);
3564 }
3565
3566 return result;
3567}
3568
3569static CTLineRef
3570mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3571 CTFontRef macfont)
3572{
3573 CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3574 CFTypeRef values[] = {NULL, NULL};
3575 CFDictionaryRef attributes = NULL;
3576 CFAttributedStringRef attr_string = NULL;
3577 CTLineRef ctline = NULL;
3578 float float_zero = 0.0f;
3579
3580 values[0] = macfont;
3581 values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3582 if (values[1])
3583 {
3584 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3585 (const void **) values,
705cf384 3586 EARRAYSIZE (keys),
d93ab42e
JD
3587 &kCFTypeDictionaryKeyCallBacks,
3588 &kCFTypeDictionaryValueCallBacks);
3589 CFRelease (values[1]);
3590 }
3591 if (attributes)
3592 {
3593 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3594 CFRelease (attributes);
3595 }
3596 if (attr_string)
3597 {
3598 ctline = CTLineCreateWithAttributedString (attr_string);
3599 CFRelease (attr_string);
3600 }
3601 if (ctline)
3602 {
3603 /* Abandon if ctline contains some fonts other than the
3604 specified one. */
3605 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3606 CFIndex i, nruns = CFArrayGetCount (runs);
3607
3608 for (i = 0; i < nruns; i++)
3609 {
3610 CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3611 CFDictionaryRef attributes = CTRunGetAttributes (run);
3612 CTFontRef font_in_run;
3613
3614 if (attributes == NULL)
3615 break;
3616 font_in_run =
3617 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3618 if (font_in_run == NULL)
3619 break;
3620 if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3621 break;
3622 }
3623 if (i < nruns)
3624 {
3625 CFRelease (ctline);
3626 ctline = NULL;
3627 }
3628 }
3629
3630 return ctline;
3631}
3632
5ee29210 3633static CFIndex
d93ab42e
JD
3634mac_ctfont_shape (CTFontRef font, CFStringRef string,
3635 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3636{
3637 CFIndex used, result = 0;
3638 CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3639
3640 if (ctline == NULL)
3641 return 0;
3642
3643 used = CTLineGetGlyphCount (ctline);
3644 if (used <= glyph_len)
3645 {
3646 CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3647 CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3648 CGFloat total_advance = 0;
3649 CFIndex total_glyph_count = 0;
3650
3651 for (k = 0; k < ctrun_count; k++)
3652 {
3653 CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3654 CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3655 struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3656 CFRange string_range, comp_range, range;
3657 CFIndex *permutation;
3658
3659 if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3660 permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3661 else
3662 permutation = NULL;
3663
3664#define RIGHT_TO_LEFT_P permutation
3665
3666 /* Now the `comp_range' member of struct mac_glyph_layout is
3667 temporarily used as a work area such that:
3668 glbuf[i].comp_range.location =
3669 min {compRange[i + 1].location, ...,
3670 compRange[glyph_count - 1].location,
3671 maxRange (stringRangeForCTRun)}
3672 glbuf[i].comp_range.length = maxRange (compRange[i])
3673 where compRange[i] is the range of composed characters
3674 containing i-th glyph. */
3675 string_range = CTRunGetStringRange (ctrun);
3676 min_location = string_range.location + string_range.length;
3677 for (i = 0; i < glyph_count; i++)
3678 {
3679 struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3680 CFIndex glyph_index;
3681 CFRange rng;
3682
3683 if (!RIGHT_TO_LEFT_P)
3684 glyph_index = glyph_count - i - 1;
3685 else
3686 glyph_index = i;
3687 CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3688 &gl->string_index);
3689 rng =
3690 CFStringGetRangeOfComposedCharactersAtIndex (string,
3691 gl->string_index);
3692 gl->comp_range.location = min_location;
3693 gl->comp_range.length = rng.location + rng.length;
3694 if (rng.location < min_location)
3695 min_location = rng.location;
3696 }
3697
3698 /* Fill the `comp_range' member of struct mac_glyph_layout,
3699 and setup a permutation for right-to-left text. */
3700 comp_range = CFRangeMake (string_range.location, 0);
3701 range = CFRangeMake (0, 0);
3702 while (1)
3703 {
3704 struct mac_glyph_layout *gl =
3705 glbuf + range.location + range.length;
3706
3707 if (gl->comp_range.length
3708 > comp_range.location + comp_range.length)
3709 comp_range.length = gl->comp_range.length - comp_range.location;
3710 min_location = gl->comp_range.location;
3711 range.length++;
3712
3713 if (min_location >= comp_range.location + comp_range.length)
3714 {
3715 comp_range.length = min_location - comp_range.location;
3716 for (i = 0; i < range.length; i++)
3717 {
3718 glbuf[range.location + i].comp_range = comp_range;
3719 if (RIGHT_TO_LEFT_P)
3720 permutation[range.location + i] =
3721 range.location + range.length - i - 1;
3722 }
3723
3724 comp_range = CFRangeMake (min_location, 0);
3725 range.location += range.length;
3726 range.length = 0;
3727 if (range.location == glyph_count)
3728 break;
3729 }
3730 }
3731
3732 /* Then fill the remaining members. */
3733 for (range = CFRangeMake (0, 1); range.location < glyph_count;
3734 range.location++)
3735 {
3736 struct mac_glyph_layout *gl;
3737 CGPoint position;
3738
3739 if (!RIGHT_TO_LEFT_P)
3740 gl = glbuf + range.location;
3741 else
3742 {
3743 CFIndex src, dest;
3744
3745 src = glyph_count - 1 - range.location;
3746 dest = permutation[src];
3747 gl = glbuf + dest;
3748 if (src < dest)
3749 {
3750 CFIndex tmp = gl->string_index;
3751
3752 gl->string_index = glbuf[src].string_index;
3753 glbuf[src].string_index = tmp;
3754 }
3755 }
3756 CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3757
3758 CTRunGetPositions (ctrun, range, &position);
3759 gl->advance_delta = position.x - total_advance;
3760 gl->baseline_delta = position.y;
3761 gl->advance = (gl->advance_delta
3762 + CTRunGetTypographicBounds (ctrun, range,
3763 NULL, NULL, NULL));
3764 total_advance += gl->advance;
3765 }
3766
3767 if (RIGHT_TO_LEFT_P)
3768 xfree (permutation);
3769
3770#undef RIGHT_TO_LEFT_P
3771
3772 total_glyph_count += glyph_count;
3773 }
3774
3775 result = used;
3776 }
3777 CFRelease (ctline);
3778
3779 return result;
3780}
3781
3782/* The function below seems to cause a memory leak for the CFString
3783 created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3784 10.6.3. For now, we use the NSGlyphInfo version instead. */
3785#if USE_CT_GLYPH_INFO
5ee29210 3786static CGGlyph
d93ab42e
JD
3787mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3788 CGFontIndex cid)
3789{
3790 CGGlyph result = kCGFontIndexInvalid;
3791 UniChar characters[] = {0xfffd};
3792 CFStringRef string;
3793 CFAttributedStringRef attr_string = NULL;
3794 CTLineRef ctline = NULL;
3795
3796 string = CFStringCreateWithCharacters (NULL, characters,
705cf384
DC
3797 EARRAYSIZE (characters));
3798
d93ab42e
JD
3799 if (string)
3800 {
3801 CTGlyphInfoRef glyph_info =
3802 CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3803 CFDictionaryRef attributes = NULL;
3804
3805 if (glyph_info)
3806 {
3807 CFStringRef keys[] = {kCTFontAttributeName,
3808 kCTGlyphInfoAttributeName};
3809 CFTypeRef values[] = {font, glyph_info};
3810
3811 attributes = CFDictionaryCreate (NULL, (const void **) keys,
3812 (const void **) values,
705cf384 3813 EARRAYSIZE (keys),
d93ab42e
JD
3814 &kCFTypeDictionaryKeyCallBacks,
3815 &kCFTypeDictionaryValueCallBacks);
3816 CFRelease (glyph_info);
3817 }
3818 if (attributes)
3819 {
3820 attr_string = CFAttributedStringCreate (NULL, string, attributes);
3821 CFRelease (attributes);
3822 }
3823 CFRelease (string);
3824 }
3825 if (attr_string)
3826 {
3827 ctline = CTLineCreateWithAttributedString (attr_string);
3828 CFRelease (attr_string);
3829 }
3830 if (ctline)
3831 {
3832 CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3833
3834 if (CFArrayGetCount (runs) > 0)
3835 {
3836 CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3837 CFDictionaryRef attributes = CTRunGetAttributes (run);
3838
3839 if (attributes)
3840 {
3841 CTFontRef font_in_run =
3842 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3843
3844 if (font_in_run
3845 && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3846 {
3847 CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3848 if (result >= CTFontGetGlyphCount (font))
3849 result = kCGFontIndexInvalid;
3850 }
3851 }
3852 }
3853 CFRelease (ctline);
3854 }
3855
3856 return result;
3857}
3858#endif
3859
3860#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3861static inline int
3862mac_font_family_group (CFStringRef family)
3863{
3864 if (CFStringHasPrefix (family, CFSTR ("#")))
3865 return 2;
3866 else
3867 {
3868 CFRange range;
3869
3870 range = CFStringFind (family, CFSTR ("Apple"),
3871 kCFCompareCaseInsensitive | kCFCompareAnchored);
3872 if (range.location != kCFNotFound)
3873 return 1;
3874
3875 return 0;
3876 }
3877}
3878
5ee29210 3879static CFComparisonResult
d93ab42e
JD
3880mac_font_family_compare (const void *val1, const void *val2, void *context)
3881{
3882 CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3883 int group1, group2;
3884
3885 group1 = mac_font_family_group (family1);
3886 group2 = mac_font_family_group (family2);
3887 if (group1 < group2)
3888 return kCFCompareLessThan;
3889 if (group1 > group2)
3890 return kCFCompareGreaterThan;
3891 return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3892}
3893#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3894
5ee29210
JD
3895static CFArrayRef
3896mac_font_copy_default_descriptors_for_language (CFStringRef language)
3897{
3898 CFArrayRef result = NULL;
3899
3900#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3901#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3902 if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3903#endif
3904 {
3905 CTFontRef user_font =
3906 CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3907
3908 if (user_font)
3909 {
3910 CFArrayRef languages =
3911 CFArrayCreate (NULL, (const void **) &language, 1,
3912 &kCFTypeArrayCallBacks);
3913
3914 if (languages)
3915 {
3916 result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3917 languages);
3918 CFRelease (languages);
3919 }
3920 CFRelease (user_font);
3921 }
3922 }
3923#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3924 else /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3925#endif
3926#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3927#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3928 {
3929 CFIndex i;
3930
3931 for (i = 0; macfont_language_default_font_names[i].language; i++)
3932 {
3933 if (CFStringCompare (macfont_language_default_font_names[i].language,
3934 language, 0) == kCFCompareEqualTo)
3935 {
3936 CFMutableArrayRef descriptors =
3937 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3938
3939 if (descriptors)
3940 {
3941 CFIndex j;
3942
3943 for (j = 0;
3944 macfont_language_default_font_names[i].font_names[j];
3945 j++)
3946 {
3947 CFDictionaryRef attributes =
3948 CFDictionaryCreate (NULL,
3949 ((const void **)
3950 &MAC_FONT_NAME_ATTRIBUTE),
3951 ((const void **)
3952 &macfont_language_default_font_names[i].font_names[j]),
3953 1, &kCFTypeDictionaryKeyCallBacks,
3954 &kCFTypeDictionaryValueCallBacks);
3955
3956 if (attributes)
3957 {
3958 FontDescriptorRef pat_desc =
3959 mac_font_descriptor_create_with_attributes (attributes);
3960
3961 if (pat_desc)
3962 {
3963 FontDescriptorRef descriptor =
3964 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3965
3966 if (descriptor)
3967 {
3968 CFArrayAppendValue (descriptors, descriptor);
3969 CFRelease (descriptor);
3970 }
3971 CFRelease (pat_desc);
3972 }
3973 CFRelease (attributes);
3974 }
3975 }
3976 result = descriptors;
3977 }
3978 break;
3979 }
3980 }
3981 }
3982#endif
3983
3984 return result;
3985}
3986
3987static CFStringRef
3988mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3989 CFArrayRef languages)
3990{
3991 CFStringRef result = NULL;
3992 CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3993 CFArrayRef descriptors =
3994 mac_font_copy_default_descriptors_for_language (language);
3995
3996 if (descriptors)
3997 {
3998 CFIndex i, count = CFArrayGetCount (descriptors);
3999
4000 for (i = 0; i < count; i++)
4001 {
4002 FontDescriptorRef descriptor =
4003 CFArrayGetValueAtIndex (descriptors, i);
4004
4005 if (macfont_supports_charset_and_languages_p (descriptor, charset,
4006 Qnil, languages))
4007 {
4008 CFStringRef family =
4009 mac_font_descriptor_copy_attribute (descriptor,
4010 MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4011 if (family)
4012 {
4013 if (!CFStringHasPrefix (family, CFSTR ("."))
4014 && (CFStringCompare (family, CFSTR ("LastResort"), 0)
4015 != kCFCompareEqualTo))
4016 {
4017 result = family;
4018 break;
4019 }
4020 else
4021 CFRelease (family);
4022 }
4023 }
4024 }
4025 CFRelease (descriptors);
4026 }
4027
4028 return result;
4029}
4030
d93ab42e
JD
4031void *
4032macfont_get_nsctfont (struct font *font)
4033{
4034 struct macfont_info *macfont_info = (struct macfont_info *) font;
4035 FontRef macfont = macfont_info->macfont;
4036
4037 return (void *) macfont;
4038}
4039
4040void
4041mac_register_font_driver (struct frame *f)
4042{
4043 register_font_driver (&macfont_driver, f);
4044}
4045
4046#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4047
4048\f
4049void
4050syms_of_macfont (void)
4051{
4052#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4053 static struct font_driver mac_font_driver;
4054
4055 DEFSYM (Qmac_ct, "mac-ct");
4056 macfont_driver.type = Qmac_ct;
4057 register_font_driver (&macfont_driver, NULL);
4058
4059 DEFSYM (QCdestination, ":destination");
4060 DEFSYM (QCminspace, ":minspace");
4061#endif
4062}