* lisp/vc/pcvs.el (cvs-cleanup-collection): Extend meaning of `rm-handled'.
[emacs.git] / src / nsfont.m
blobc0bea2e225cfaee7a82933d75f78ba75176a96ff
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006-2013 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
23 /* This should be the first include, as it may set up #defines affecting
24    interpretation of even the system includes. */
25 #include <config.h>
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
31 #include "charset.h"
32 #include "frame.h"
33 #include "window.h"
34 #include "fontset.h"
35 #include "nsterm.h"
36 #include "frame.h"
37 #include "character.h"
38 #include "font.h"
39 #include "termchar.h"
41 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
42 #ifdef NS_IMPL_GNUSTEP
43 #import <AppKit/NSFontDescriptor.h>
44 #endif
46 #define NSFONT_TRACE 0
48 extern Lisp_Object Qns;
49 extern Lisp_Object Qnormal, Qbold, Qitalic;
50 static Lisp_Object Qapple, Qroman, Qmedium;
51 static Lisp_Object Qcondensed, Qexpanded;
52 extern Lisp_Object Qappend;
53 extern float ns_antialias_threshold;
54 extern int ns_tmp_flags;
55 extern struct nsfont_info *ns_tmp_font;
58 /* font glyph and metrics caching functions, implemented at end */
59 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
60                               unsigned char block);
61 static void ns_glyph_metrics (struct nsfont_info *font_info,
62                               unsigned char block);
65 /* ==========================================================================
67     Utilities
69    ========================================================================== */
72 /* Replace spaces w/another character so emacs core font parsing routines
73    aren't thrown off. */
74 static void
75 ns_escape_name (char *name)
77   int i =0, len =strlen (name);
78   for ( ; i<len; i++)
79     if (name[i] == ' ')
80       name[i] = '_';
84 /* Reconstruct spaces in a font family name passed through emacs. */
85 static void
86 ns_unescape_name (char *name)
88   int i =0, len =strlen (name);
89   for ( ; i<len; i++)
90     if (name[i] == '_')
91       name[i] = ' ';
95 /* Extract family name from a font spec. */
96 static NSString *
97 ns_get_family (Lisp_Object font_spec)
99   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
100   if (NILP (tem))
101       return nil;
102   else
103     {
104       char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
105       NSString *family;
106       ns_unescape_name (tmp);
107       family = [NSString stringWithUTF8String: tmp];
108       xfree (tmp);
109       return family;
110     }
114 /* Return 0 if attr not set, else value (which might also be 0).
115    On Leopard 0 gets returned even on descriptors where the attribute
116    was never set, so there's no way to distinguish between unspecified
117    and set to not have.  Callers should assume 0 means unspecified. */
118 static float
119 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
121     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
122     NSNumber *val = [tdict objectForKey: trait];
123     return val == nil ? 0.0 : [val floatValue];
127 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
128    to NSFont descriptor.  Information under extra only needed for matching. */
129 #define STYLE_REF 100
130 static NSFontDescriptor *
131 ns_spec_to_descriptor (Lisp_Object font_spec)
133     NSFontDescriptor *fdesc;
134     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
135     NSMutableDictionary *tdict = [NSMutableDictionary new];
136     NSString *family = ns_get_family (font_spec);
137     float n;
139     /* add each attr in font_spec to fdAttrs.. */
140     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
141     if (n != -1 && n != STYLE_REF)
142         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
143                   forKey: NSFontWeightTrait];
144     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
145     if (n != -1 && n != STYLE_REF)
146         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
147                   forKey: NSFontSlantTrait];
148     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
149     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
150         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
151                   forKey: NSFontWidthTrait];
152     if ([tdict count] > 0)
153         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
155     fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
156     if (family != nil)
157       {
158         fdesc = [fdesc fontDescriptorWithFamily: family];
159       }
161     [fdAttrs release];
162     [tdict release];
163     return fdesc;
167 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
168 static Lisp_Object
169 ns_descriptor_to_entity (NSFontDescriptor *desc,
170                          Lisp_Object extra,
171                          const char *style)
173     Lisp_Object font_entity = font_make_entity ();
174     /*   NSString *psName = [desc postscriptName]; */
175     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
176     unsigned int traits = [desc symbolicTraits];
177     char *escapedFamily;
179     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
180     if (family == nil)
181       family = [desc objectForKey: NSFontNameAttribute];
182     if (family == nil)
183       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
185     escapedFamily = xstrdup ([family UTF8String]);
186     ns_escape_name (escapedFamily);
188     ASET (font_entity, FONT_TYPE_INDEX, Qns);
189     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
190     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
191     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
192     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
194     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
195                     traits & NSFontBoldTrait ? Qbold : Qmedium);
196 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
197                     make_number (100 + 100
198                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
199     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
200                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
201 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
202                     make_number (100 + 100
203                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
204     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
205                     traits & NSFontCondensedTrait ? Qcondensed :
206                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
207 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
208                     make_number (100 + 100
209                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
211     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
212     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
213     ASET (font_entity, FONT_SPACING_INDEX,
214           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
215               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
217     ASET (font_entity, FONT_EXTRA_INDEX, extra);
218     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
220     if (NSFONT_TRACE)
221       {
222         fprintf (stderr, "created font_entity:\n    ");
223         debug_print (font_entity);
224       }
226     xfree (escapedFamily);
227     return font_entity;
231 /* Default font entity. */
232 static Lisp_Object
233 ns_fallback_entity (void)
235   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
236       fontDescriptor], Qnil, NULL);
240 /* Utility: get width of a char c in screen font SFONT */
241 static float
242 ns_char_width (NSFont *sfont, int c)
244   float w = -1.0;
245   NSString *cstr = [NSString stringWithFormat: @"%c", c];
247 #ifdef NS_IMPL_COCOA
248   NSGlyph glyph = [sfont glyphWithName: cstr];
249   if (glyph)
250     w = [sfont advancementForGlyph: glyph].width;
251 #endif
253   if (w < 0.0)
254     {
255       NSDictionary *attrsDictionary =
256         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
257       w = [cstr sizeWithAttributes: attrsDictionary].width;
258     }
260   return max (w, 1.0);
263 /* Return average width over ASCII printable characters for SFONT.  */
265 static NSString *ascii_printable;
267 static int
268 ns_ascii_average_width (NSFont *sfont)
270   float w = -1.0;
272   if (!ascii_printable)
273     {
274       char chars[96];
275       int ch;
276       for (ch = 0; ch < 95; ch++)
277         chars[ch] = ' ' + ch;
278       chars[95] = '\0';
280       ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
281     }
283 #ifdef NS_IMPL_COCOA
284   NSGlyph glyph = [sfont glyphWithName: ascii_printable];
285   if (glyph)
286     w = [sfont advancementForGlyph: glyph].width;
287 #endif
289   if (w < 0.0)
290     {
291       NSDictionary *attrsDictionary =
292         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
293       w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
294     }
296   return lrint (w / 95.0);
300 /* Return whether set1 covers set2 to a reasonable extent given by pct.
301    We check, out of each 16 Unicode char range containing chars in set2,
302    whether at least one character is present in set1.
303    This must be true for pct of the pairs to consider it covering. */
304 static BOOL
305 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
307     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
308     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
309     int i, off = 0, tot = 0;
311     /* Work around what appears to be a GNUstep bug.
312        See <http://bugs.gnu.org/11853>.  */
313     if (! (bytes1 && bytes2))
314       return NO;
316     for (i=0; i<4096; i++, bytes1++, bytes2++)
317         if (*bytes2)
318           {
319             tot++;
320             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
321                 off++;
322           }
323 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
324     return (float)off / tot < 1.0 - pct;
328 /* Convert :lang property to a script.  Use of :lang property by font backend
329    seems to be limited for now (2009/05) to ja, zh, and ko. */
330 static NSString
331 *ns_lang_to_script (Lisp_Object lang)
333     if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
334         return @"han";
335     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
336              have more characters. */
337     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
338         return @"han";
339     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
340         return @"hangul";
341     else
342         return @"";
346 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
347    everyone just use some standard Unicode names for these?) */
348 static NSString
349 *ns_otf_to_script (Lisp_Object otf)
351     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
352     return CONSP (script)
353         ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
354         : @"";
358 /* Convert a font registry, such as  */
359 static NSString
360 *ns_registry_to_script (char *reg)
362     Lisp_Object script, r, rts = Vns_reg_to_script;
363     while CONSP (rts)
364       {
365         r = XCAR (XCAR (rts));
366         if (!strncmp(SSDATA(r), reg, strlen(SSDATA(r))))
367           {
368             script = XCDR (XCAR (rts));
369             return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
370           }
371         rts = XCDR (rts);
372       }
373     return  @"";
377 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
378    plus registry regular property, for something that can be mapped to a
379    Unicode script.  Empty string returned if no script spec found. */
380 static NSString
381 *ns_get_req_script (Lisp_Object font_spec)
383     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
384     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
386     /* The extra-bundle properties have priority. */
387     for ( ; CONSP (extra); extra = XCDR (extra))
388       {
389         Lisp_Object tmp = XCAR (extra);
390         if (CONSP (tmp))
391           {
392             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
393             if (EQ (key, QCscript) && SYMBOLP (val))
394                 return [NSString stringWithUTF8String:
395                             SSDATA (SYMBOL_NAME (val))];
396             if (EQ (key, QClang) && SYMBOLP (val))
397                 return ns_lang_to_script (val);
398             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
399                 return ns_otf_to_script (val);
400           }
401       }
403     /* If we get here, check the charset portion of the registry. */
404     if (! NILP (reg))
405       {
406         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
407            (which causes box rendering if we don't treat it like iso8858-1)
408            but also for ascii (which causes unnecessary font substitution). */
409 #if 0
410         if (EQ (reg, Qiso10646_1))
411           reg = Qiso8859_1;
412 #endif
413         return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
414       }
416     return @"";
420 /* This small function is static in fontset.c.  If it can be made public for
421    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
422 static void
423 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
425     if (EQ (XCAR (arg), val))
426       {
427         if (CONSP (range))
428           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
429         else
430           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
431       }
435 /* Use the Unicode range information in Vchar_script_table to convert a script
436    name into an NSCharacterSet. */
437 static NSCharacterSet
438 *ns_script_to_charset (NSString *scriptName)
440     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
441     Lisp_Object script = intern ([scriptName UTF8String]);
442     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
444     if (! NILP (Fmemq (script, script_list)))
445       {
446         Lisp_Object ranges, range_list;
448         ranges = Fcons (script, Qnil);
449         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
450                         ranges);
451         range_list = Fnreverse (XCDR (ranges));
452         if (! NILP (range_list))
453           {
454             for (; CONSP (range_list); range_list = XCDR (range_list))
455               {
456                 int start = XINT (XCAR (XCAR (range_list)));
457                 int end = XINT (XCDR (XCAR (range_list)));
458                 if (NSFONT_TRACE)
459                     debug_print (XCAR (range_list));
460                 if (end < 0x10000)
461                     [charset addCharactersInRange:
462                         NSMakeRange (start, end-start)];
463               }
464           }
465       }
466     return charset;
470 /* Return an array of font families containing characters for the given
471    script, for the given coverage criterion, including at least LastResort.
472    Results are cached by script for faster access.
473    If none are found, we reduce the percentage and try again, until 5%.
474    This provides a font with at least some characters if such can be found.
475    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
476    (b) need approximate match as fonts covering full Unicode ranges are rare. */
477 static NSSet
478 *ns_get_covering_families (NSString *script, float pct)
480     static NSMutableDictionary *scriptToFamilies = nil;
481     NSMutableSet *families;
483     if (NSFONT_TRACE)
484         NSLog(@"Request covering families for script: '%@'", script);
486     if (scriptToFamilies == nil)
487         scriptToFamilies = [[NSMutableDictionary alloc] init];
489     if ((families = [scriptToFamilies objectForKey: script]) == nil)
490       {
491         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
492         NSArray *allFamilies = [fontMgr availableFontFamilies];
494         if ([script length] == 0)
495             families = [NSMutableSet setWithArray: allFamilies];
496         else
497           {
498             NSCharacterSet *charset = ns_script_to_charset (script);
499             NSString *family;
500             families = [NSMutableSet setWithCapacity: 10];
501             while (1)
502               {
503                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
504                 while ((family = [allFamiliesEnum nextObject]))
505                   {
506                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
507                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
508                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
509                     if (fset == nil)
510                       fset = [NSCharacterSet characterSetWithRange:
511                                                NSMakeRange (0, 127)];
512                     if (ns_charset_covers(fset, charset, pct))
513                         [families addObject: family];
514                   }
515                 pct -= 0.2;
516                 if ([families count] > 0 || pct < 0.05)
517                     break;
518               }
519             [charset release];
520           }
521 #ifdef NS_IMPL_COCOA
522         if ([families count] == 0)
523             [families addObject: @"LastResort"];
524 #endif
525         [scriptToFamilies setObject: families forKey: script];
526       }
528     if (NSFONT_TRACE)
529         NSLog(@"    returning %d families", [families count]);
530     return families;
534 /* Implementation for list() and match().  List() can return nil, match()
535 must return something.  Strategy is to drop family name from attribute
536 matching set for match. */
537 static Lisp_Object
538 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
540     Lisp_Object tem, list = Qnil;
541     NSFontDescriptor *fdesc, *desc;
542     NSMutableSet *fkeys;
543     NSArray *matchingDescs;
544     NSEnumerator *dEnum;
545     NSString *family;
546     NSSet *cFamilies;
547     BOOL foundItal = NO;
549     if (NSFONT_TRACE)
550       {
551         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
552                  (isMatch ? "match" : "list"));
553         debug_print (font_spec);
554       }
556     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
558     fdesc = ns_spec_to_descriptor (font_spec);
559     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
560     if (isMatch)
561         [fkeys removeObject: NSFontFamilyAttribute];
563     if ([fkeys count] > 0)
564       matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
565     else
566       matchingDescs = [NSMutableArray array];
568     if (NSFONT_TRACE)
569         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
570               [matchingDescs count]);
572     for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
573       {
574         if (![cFamilies containsObject:
575                  [desc objectForKey: NSFontFamilyAttribute]])
576             continue;
577         tem = ns_descriptor_to_entity (desc,
578                                          AREF (font_spec, FONT_EXTRA_INDEX),
579                                        NULL);
580         if (isMatch)
581           return tem;
582         list = Fcons (tem, list);
583         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
584             foundItal = YES;
585       }
587     /* Add synthItal member if needed. */
588     family = [fdesc objectForKey: NSFontFamilyAttribute];
589     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
590       {
591         NSFontDescriptor *s1 = [NSFontDescriptor new];
592         NSFontDescriptor *sDesc
593           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
594               fontDescriptorWithFamily: family];
595         list = Fcons (ns_descriptor_to_entity (sDesc,
596                                          AREF (font_spec, FONT_EXTRA_INDEX),
597                                          "synthItal"), list);
598         [s1 release];
599       }
601     /* Return something if was a match and nothing found. */
602     if (isMatch)
603       return ns_fallback_entity ();
605     if (NSFONT_TRACE)
606         fprintf (stderr, "    Returning %"pI"d entities.\n",
607                  XINT (Flength (list)));
609     return list;
614 /* ==========================================================================
616     Font driver implementation
618    ========================================================================== */
621 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
622 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
623 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
624 static Lisp_Object nsfont_list_family (Lisp_Object frame);
625 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
626                                  int pixel_size);
627 static void nsfont_close (FRAME_PTR f, struct font *font);
628 static int nsfont_has_char (Lisp_Object entity, int c);
629 static unsigned int nsfont_encode_char (struct font *font, int c);
630 static int nsfont_text_extents (struct font *font, unsigned int *code,
631                                 int nglyphs, struct font_metrics *metrics);
632 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
633                         bool with_background);
635 struct font_driver nsfont_driver =
636   {
637     0,                          /* Qns */
638     1,                          /* case sensitive */
639     nsfont_get_cache,
640     nsfont_list,
641     nsfont_match,
642     nsfont_list_family,
643     NULL,                       /*free_entity */
644     nsfont_open,
645     nsfont_close,
646     NULL,                       /* prepare_face */
647     NULL,                       /* done_face */
648     nsfont_has_char,
649     nsfont_encode_char,
650     nsfont_text_extents,
651     nsfont_draw,
652     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
653                  anchor_point, otf_capability, otf_driver,
654                  start_for_frame, end_for_frame, shape */
655   };
658 /* Return a cache of font-entities on FRAME.  The cache must be a
659    cons whose cdr part is the actual cache area.  */
660 static Lisp_Object
661 nsfont_get_cache (FRAME_PTR frame)
663   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
664   return (dpyinfo->name_list_element);
668 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
669    **list** of font-entities.  This and match () are sole APIs that allocate
670    font-entities.  Properties to be considered (2009/05/19) are:
671    regular: foundry, family, adstyle, registry
672    extended: script, lang, otf
673   "Extended" properties are not part of the vector but get stored as
674    lisp properties under FONT_EXTRA_INDEX.
676    The returned entities should have type set (to 'ns), plus the following:
677    foundry, family, adstyle, registry,
678    weight, slant, width, size (0 if scalable),
679    dpi, spacing, avgwidth (0 if scalable)  */
680 static Lisp_Object
681 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
683     return ns_findfonts (font_spec, NO);
687 /* Return a font entity most closely matching with FONT_SPEC on
688    FRAME.  The closeness is determined by the font backend, thus
689    `face-font-selection-order' is ignored here.
690    Properties to be considered are same as for list(). */
691 static Lisp_Object
692 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
694     return ns_findfonts(font_spec, YES);
698 /* List available families.  The value is a list of family names
699    (symbols). */
700 static Lisp_Object
701 nsfont_list_family (Lisp_Object frame)
703   Lisp_Object list = Qnil;
704   NSEnumerator *families =
705     [[[NSFontManager sharedFontManager] availableFontFamilies]
706       objectEnumerator];
707   NSString *family;
708   while ((family = [families nextObject]))
709       list = Fcons (intern ([family UTF8String]), list);
710   /* FIXME: escape the name? */
712   if (NSFONT_TRACE)
713     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
714              XINT (Flength (list)));
716   return list;
720 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
721    scalable, open it with PIXEL_SIZE.  */
722 static Lisp_Object
723 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
725   BOOL synthItal;
726   unsigned int traits = 0;
727   struct nsfont_info *font_info;
728   struct font *font;
729   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
730   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
731   NSString *family;
732   NSFont *nsfont, *sfont;
733   Lisp_Object tem;
734   NSRect brect;
735   Lisp_Object font_object;
736   int fixLeopardBug;
738   if (NSFONT_TRACE)
739     {
740       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
741       debug_print (font_entity);
742     }
744   if (pixel_size <= 0)
745     {
746       /* try to get it out of frame params */
747         Lisp_Object tem = get_frame_param (f, Qfontsize);
748         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
749     }
751   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
752   synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
753                                        9);
754   family = ns_get_family (font_entity);
755   if (family == nil)
756     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
757   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
758      when setting family in ns_spec_to_descriptor(). */
759   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
760       traits |= NSBoldFontMask;
761   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
762       traits |= NSItalicFontMask;
764   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
765   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
766   nsfont = [fontMgr fontWithFamily: family
767                             traits: traits weight: fixLeopardBug
768                               size: pixel_size];
769   /* if didn't find, try synthetic italic */
770   if (nsfont == nil && synthItal)
771     {
772       nsfont = [fontMgr fontWithFamily: family
773                                 traits: traits & ~NSItalicFontMask
774                                 weight: fixLeopardBug size: pixel_size];
775     }
776 #ifdef NS_IMPL_COCOA
777   /* LastResort not really a family */
778   if (nsfont == nil && [@"LastResort" isEqualToString: family])
779       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
780 #endif
782   if (nsfont == nil)
783     {
784       message_with_string ("*** Warning: font in family '%s' not found",
785                           build_string ([family UTF8String]), 1);
786       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
787     }
789   if (NSFONT_TRACE)
790     NSLog (@"%@\n", nsfont);
792   font_object = font_make_object (VECSIZE (struct nsfont_info),
793                                   font_entity, pixel_size);
794   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
795   font = (struct font *) font_info;
796   if (!font)
797     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
799   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
800   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
802   block_input ();
804   /* for metrics */
805 #ifdef NS_IMPL_COCOA
806   sfont = [nsfont screenFontWithRenderingMode:
807                     NSFontAntialiasedIntegerAdvancementsRenderingMode];
808 #else
809   sfont = [nsfont screenFont];
810 #endif
812   if (sfont == nil)
813     sfont = nsfont;
815   /* non-metric backend font struct fields */
816   font = (struct font *) font_info;
817   font->pixel_size = [sfont pointSize];
818   font->driver = &nsfont_driver;
819   font->encoding_charset = -1;
820   font->repertory_charset = -1;
821   font->default_ascent = 0;
822   font->vertical_centering = 0;
823   font->baseline_offset = 0;
824   font->relative_compose = 0;
825   font->font_encoder = NULL;
827   font->props[FONT_FORMAT_INDEX] = Qns;
828   font->props[FONT_FILE_INDEX] = Qnil;
830   {
831     const char *fontName = [[nsfont fontName] UTF8String];
833     /* The values specified by fonts are not always exact. For
834      * example, a 6x8 font could specify that the descender is
835      * -2.00000405... (represented by 0xc000000220000000).  Without
836      * adjustment, the code below would round the descender to -3,
837      * resulting in a font that would be one pixel higher than
838      * intended. */
839     CGFloat adjusted_descender = [sfont descender] + 0.0001;
841 #ifdef NS_IMPL_GNUSTEP
842     font_info->nsfont = sfont;
843 #else
844     font_info->nsfont = nsfont;
845 #endif
846     [font_info->nsfont retain];
848     /* set up ns_font (defined in nsgui.h) */
849     font_info->name = xstrdup (fontName);
850     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
851     font_info->ital =
852       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
854     /* Metrics etc.; some fonts return an unusually large max advance, so we
855        only use it for fonts that have wide characters. */
856     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
857       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
859     brect =  [sfont boundingRectForFont];
861     font_info->underpos = [sfont underlinePosition];
862     font_info->underwidth = [sfont underlineThickness];
863     font_info->size = font->pixel_size;
865     /* max bounds */
866     font_info->max_bounds.ascent = lrint ([sfont ascender]);
867     /* Descender is usually negative.  Use floor to avoid
868        clipping descenders. */
869     font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
870     font_info->height =
871       font_info->max_bounds.ascent + font_info->max_bounds.descent;
872     font_info->max_bounds.width = lrint (font_info->width);
873     font_info->max_bounds.lbearing = lrint (brect.origin.x);
874     font_info->max_bounds.rbearing =
875       lrint (brect.size.width - font_info->width);
877 #ifdef NS_IMPL_COCOA
878     /* set up synthItal and the CG font */
879     font_info->synthItal = synthItal;
880     {
881       ATSFontRef atsFont = ATSFontFindFromPostScriptName
882         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
884       if (atsFont == kATSFontRefUnspecified)
885         {
886           /* see if we can get it by dropping italic (then synthesizing) */
887           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
888               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
889                 fontName], kATSOptionFlagsDefault);
890           if (atsFont != kATSFontRefUnspecified)
891               font_info->synthItal = YES;
892           else
893             {
894               /* last resort fallback */
895               atsFont = ATSFontFindFromPostScriptName
896                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
897             }
898         }
899       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
900     }
901 #endif
903     /* set up metrics portion of font struct */
904     font->ascent = lrint([sfont ascender]);
905     font->descent = -lrint(floor(adjusted_descender));
906     font->space_width = lrint (ns_char_width (sfont, ' '));
907     font->max_width = lrint (font_info->max_bounds.width);
908     font->min_width = font->space_width;  /* Approximate.  */
909     font->average_width = ns_ascii_average_width (sfont);
911     font->height = lrint (font_info->height);
912     font->underline_position = lrint (font_info->underpos);
913     font->underline_thickness = lrint (font_info->underwidth);
915     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
916     font->props[FONT_FULLNAME_INDEX] =
917       make_unibyte_string (font_info->name, strlen (font_info->name));
918   }
919   unblock_input ();
921   return font_object;
925 /* Close FONT on frame F. */
926 static void
927 nsfont_close (FRAME_PTR f, struct font *font)
929   struct nsfont_info *font_info = (struct nsfont_info *)font;
930   int i;
932   /* FIXME: this occurs apparently due to same failure to detect same font
933             that causes need for cache in nsfont_open () */
934   if (!font_info)
935       return;
937   for (i =0; i<0x100; i++)
938     {
939       xfree (font_info->glyphs[i]);
940       xfree (font_info->metrics[i]);
941     }
942   [font_info->nsfont release];
943 #ifdef NS_IMPL_COCOA
944   CGFontRelease (font_info->cgfont);
945 #endif
946   xfree (font_info->name);
947   xfree (font_info);
951 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
952    return 1.  If not, return 0.  If a font must be opened to check
953    it, return -1. */
954 static int
955 nsfont_has_char (Lisp_Object entity, int c)
957   return -1;
961 /* Return a glyph code of FONT for character C (Unicode code point).
962    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
963 static unsigned int
964 nsfont_encode_char (struct font *font, int c)
966   struct nsfont_info *font_info = (struct nsfont_info *)font;
967   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
968   unsigned short g;
970   if (c > 0xFFFF)
971     return FONT_INVALID_CODE;
973   /* did we already cache this block? */
974   if (!font_info->glyphs[high])
975     ns_uni_to_glyphs (font_info, high);
977   g = font_info->glyphs[high][low];
978   return g == 0xFFFF ? FONT_INVALID_CODE : g;
982 /* Perform the size computation of glyphs of FONT and fill in members
983    of METRICS.  The glyphs are specified by their glyph codes in
984    CODE (length NGLYPHS). */
985 static int
986 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
987                      struct font_metrics *metrics)
989   struct nsfont_info *font_info = (struct nsfont_info *)font;
990   struct font_metrics *pcm;
991   unsigned char high, low;
992   int totalWidth = 0;
993   int i;
995   memset (metrics, 0, sizeof (struct font_metrics));
997   for (i =0; i<nglyphs; i++)
998     {
999       /* get metrics for this glyph, filling cache if need be */
1000       /* TODO: get metrics for whole string from an NSLayoutManager
1001                (if not too slow) */
1002       high = (code[i] & 0xFF00) >> 8;
1003       low = code[i] & 0x00FF;
1004       if (!font_info->metrics[high])
1005         ns_glyph_metrics (font_info, high);
1006       pcm = &(font_info->metrics[high][low]);
1008       if (metrics->lbearing > totalWidth + pcm->lbearing)
1009         metrics->lbearing = totalWidth + pcm->lbearing;
1010       if (metrics->rbearing < totalWidth + pcm->rbearing)
1011         metrics->rbearing = totalWidth + pcm->rbearing;
1012       if (metrics->ascent < pcm->ascent)
1013         metrics->ascent = pcm->ascent;
1014       if (metrics->descent < pcm->descent)
1015         metrics->descent = pcm->descent;
1017       totalWidth += pcm->width;
1018     }
1020   metrics->width = totalWidth;
1022   return totalWidth; /* not specified in doc, but xfont.c does it */
1026 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1027    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND,
1028    fill the background in advance.  It is assured that WITH_BACKGROUND
1029    is false when (FROM > 0 || TO < S->nchars). */
1030 static int
1031 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1032              bool with_background)
1033 /* NOTE: focus and clip must be set
1034      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1036   static char cbuf[1024];
1037   char *c = cbuf;
1038 #ifdef NS_IMPL_GNUSTEP
1039   static float advances[1024];
1040   float *adv = advances;
1041 #else
1042   static CGSize advances[1024];
1043   CGSize *adv = advances;
1044 #endif
1045   struct face *face;
1046   NSRect r;
1047   struct nsfont_info *font = ns_tmp_font;
1048   NSColor *col, *bgCol;
1049   unsigned short *t = s->char2b;
1050   int i, len;
1051   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1052   int end = isComposite ? s->cmp_to : s->nchars;
1054   /* Select face based on input flags */
1055   switch (ns_tmp_flags)
1056     {
1057     case NS_DUMPGLYPH_CURSOR:
1058       face = s->face;
1059       break;
1060     case NS_DUMPGLYPH_MOUSEFACE:
1061       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1062       if (!face)
1063         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1064       break;
1065     default:
1066       face = s->face;
1067     }
1069   r.origin.x = s->x;
1070   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1071     r.origin.x += abs (s->face->box_line_width);
1073   r.origin.y = s->y;
1074   r.size.height = FONT_HEIGHT (font);
1076   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1077      NS to render the string, it will come out differently from the individual
1078      character widths added up because of layout processing. */
1079   {
1080     int cwidth, twidth = 0;
1081     int hi, lo;
1082     /* FIXME: composition: no vertical displacement is considered. */
1083     t += s->cmp_from; /* advance into composition */
1084     for (i = s->cmp_from; i < end; i++, t++)
1085       {
1086         hi = (*t & 0xFF00) >> 8;
1087         lo = *t & 0x00FF;
1088         if (isComposite)
1089           {
1090             if (!s->first_glyph->u.cmp.automatic)
1091                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1092             else
1093               {
1094                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1095                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1096                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1097                     cwidth = LGLYPH_WIDTH (glyph);
1098                 else
1099                   {
1100                     cwidth = LGLYPH_WADJUST (glyph);
1101 #ifdef NS_IMPL_GNUSTEP
1102                     *(adv-1) += LGLYPH_XOFF (glyph);
1103 #else
1104                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1105 #endif
1106                   }
1107               }
1108           }
1109         else
1110           {
1111             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1112               ns_glyph_metrics (font, hi);
1113             cwidth = font->metrics[hi][lo].width;
1114           }
1115         twidth += cwidth;
1116 #ifdef NS_IMPL_GNUSTEP
1117         *adv++ = cwidth;
1118         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1119 #else
1120         (*adv++).width = cwidth;
1121 #endif
1122       }
1123     len = adv - advances;
1124     r.size.width = twidth;
1125     *c = 0;
1126   }
1128   /* fill background if requested */
1129   if (with_background && !isComposite)
1130     {
1131       NSRect br = r;
1132       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1133       int mbox_line_width = max (s->face->box_line_width, 0);
1135       if (s->row->full_width_p)
1136         {
1137           if (br.origin.x <= fibw + 1 + mbox_line_width)
1138             {
1139               br.size.width += br.origin.x - mbox_line_width;
1140               br.origin.x = mbox_line_width;
1141             }
1142           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1143                 <= fibw+1)
1144             br.size.width += fibw;
1145         }
1146       if (s->face->box == FACE_NO_BOX)
1147         {
1148           /* expand unboxed top row over internal border */
1149           if (br.origin.y <= fibw + 1 + mbox_line_width)
1150             {
1151               br.size.height += br.origin.y;
1152               br.origin.y = 0;
1153             }
1154         }
1155       else
1156         {
1157           int correction = abs (s->face->box_line_width)+1;
1158           br.origin.y += correction;
1159           br.size.height -= 2*correction;
1160           br.origin.x += correction;
1161           br.size.width -= 2*correction;
1162         }
1164       if (!s->face->stipple)
1165         [(NS_FACE_BACKGROUND (face) != 0
1166           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1167           : FRAME_BACKGROUND_COLOR (s->f)) set];
1168       else
1169         {
1170           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1171           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1172         }
1173       NSRectFill (br);
1174     }
1177   /* set up for character rendering */
1178   r.origin.y = s->ybase;
1180   col = (NS_FACE_FOREGROUND (face) != 0
1181          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1182          : FRAME_FOREGROUND_COLOR (s->f));
1183   /* FIXME: find another way to pass this */
1184   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1185            : (NS_FACE_BACKGROUND (face) != 0
1186               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1187               : FRAME_BACKGROUND_COLOR (s->f)));
1189   /* render under GNUstep using DPS */
1190 #ifdef NS_IMPL_GNUSTEP
1191   {
1192     NSGraphicsContext *context = GSCurrentContext ();
1194     DPSgsave (context);
1195     [font->nsfont set];
1197     /* do erase if "foreground" mode */
1198     if (bgCol != nil)
1199       {
1200         [bgCol set];
1201         DPSmoveto (context, r.origin.x, r.origin.y);
1202 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1203         DPSxshow (context, cbuf, advances, len);
1204         DPSstroke (context);
1205         [col set];
1206 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1207       }
1209     [col set];
1211     /* draw with DPSxshow () */
1212     DPSmoveto (context, r.origin.x, r.origin.y);
1213     DPSxshow (context, cbuf, advances, len);
1214     DPSstroke (context);
1216     DPSgrestore (context);
1217   }
1219 #else  /* NS_IMPL_COCOA */
1220   {
1221     CGContextRef gcontext =
1222       [[NSGraphicsContext currentContext] graphicsPort];
1223     static CGAffineTransform fliptf;
1224     static BOOL firstTime = YES;
1226     if (firstTime)
1227       {
1228         firstTime = NO;
1229         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1230       }
1232     CGContextSaveGState (gcontext);
1234     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1236     CGContextSetFont (gcontext, font->cgfont);
1237     CGContextSetFontSize (gcontext, font->size);
1238     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1239       CGContextSetShouldAntialias (gcontext, 0);
1240     else
1241       CGContextSetShouldAntialias (gcontext, 1);
1243     CGContextSetShouldSmoothFonts (gcontext, NO);
1244     CGContextSetTextMatrix (gcontext, fliptf);
1246     if (bgCol != nil)
1247       {
1248         /* foreground drawing; erase first to avoid overstrike */
1249         [bgCol set];
1250         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1251         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1252         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1253         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1254       }
1256     [col set];
1258     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1259     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1260                                     advances, len);
1262     if (face->overstrike)
1263       {
1264         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1265         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1266                                         advances, len);
1267       }
1269     CGContextRestoreGState (gcontext);
1270   }
1271 #endif  /* NS_IMPL_COCOA */
1273   /* Draw underline, overline, strike-through. */
1274   ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1276   return to-from;
1281 /* ==========================================================================
1283     Font glyph and metrics caching functions
1285    ========================================================================== */
1287 /* Find and cache corresponding glyph codes for unicode values in given
1288    hi-byte block of 256. */
1289 static void
1290 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1292 #ifdef NS_IMPL_COCOA
1293   static EmacsGlyphStorage *glyphStorage;
1294   static char firstTime = 1;
1295 #endif
1296   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1297   unsigned int i, g, idx;
1298   unsigned short *glyphs;
1300   if (NSFONT_TRACE)
1301     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1302             font_info, block);
1304   block_input ();
1306 #ifdef NS_IMPL_COCOA
1307   if (firstTime)
1308     {
1309       firstTime = 0;
1310       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1311     }
1312 #endif
1314   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1315   if (!unichars || !(font_info->glyphs[block]))
1316     emacs_abort ();
1318   /* create a string containing all Unicode characters in this block */
1319   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1320     if (idx < 0xD800 || idx > 0xDFFF)
1321       unichars[i] = idx;
1322     else
1323       unichars[i] = 0xFEFF;
1324   unichars[0x100] = 0;
1326   {
1327 #ifdef NS_IMPL_COCOA
1328     NSString *allChars = [[NSString alloc]
1329                                initWithCharactersNoCopy: unichars
1330                                                  length: 0x100
1331                                            freeWhenDone: NO];
1332     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1333     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1334     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1335     NSUInteger gInd = 0, cInd = 0;
1337     [glyphStorage setString: allChars font: font_info->nsfont];
1338     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1339                         desiredNumberOfCharacters: glyphStorage->maxChar
1340                                        glyphIndex: &gInd characterIndex: &cInd];
1341 #endif
1342     glyphs = font_info->glyphs[block];
1343     for (i = 0; i < 0x100; i++, glyphs++)
1344       {
1345 #ifdef NS_IMPL_GNUSTEP
1346         g = unichars[i];
1347 #else
1348         g = glyphStorage->cglyphs[i];
1349         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1350         if (g > numGlyphs)
1351           g = 0xFFFF; /* hopefully unused... */
1352 #endif
1353         *glyphs = g;
1354       }
1356 #ifdef NS_IMPL_COCOA
1357     [allChars release];
1358 #endif
1359   }
1361   unblock_input ();
1362   xfree (unichars);
1366 /* Determine and cache metrics for corresponding glyph codes in given
1367    hi-byte block of 256. */
1368 static void
1369 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1371   unsigned int i, g;
1372   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1373   NSFont *sfont;
1374   struct font_metrics *metrics;
1376   if (NSFONT_TRACE)
1377     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1378             font_info, block);
1380 #ifdef NS_IMPL_GNUSTEP
1381   /* not implemented yet (as of startup 0.18), so punt */
1382   if (numGlyphs == 0)
1383     numGlyphs = 0x10000;
1384 #endif
1386   block_input ();
1387 #ifdef NS_IMPL_COCOA
1388   sfont = [font_info->nsfont screenFontWithRenderingMode:
1389                       NSFontAntialiasedIntegerAdvancementsRenderingMode];
1390 #else
1391   sfont = [font_info->nsfont screenFont];
1392 #endif
1394   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1395   if (!(font_info->metrics[block]))
1396     emacs_abort ();
1398   metrics = font_info->metrics[block];
1399   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1400     {
1401       float w, lb, rb;
1402       NSRect r = [sfont boundingRectForGlyph: g];
1404       w = max ([sfont advancementForGlyph: g].width, 2.0);
1405       metrics->width = lrint (w);
1407       lb = r.origin.x;
1408       rb = r.size.width - w;
1409       if (lb < 0)
1410         metrics->lbearing = round (lb);
1411       if (font_info->ital)
1412         rb += 0.22 * font_info->height;
1413       metrics->rbearing = lrint (w + rb);
1415       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1416  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1417       metrics->ascent = r.size.height - metrics->descent;
1418 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1419     }
1420   unblock_input ();
1424 #ifdef NS_IMPL_COCOA
1425 /* helper for font glyph setup */
1426 @implementation EmacsGlyphStorage
1428 - init
1430   return [self initWithCapacity: 1024];
1433 - initWithCapacity: (unsigned long) c
1435   self = [super init];
1436   maxChar = 0;
1437   maxGlyph = 0;
1438   dict = [NSMutableDictionary new];
1439   cglyphs = xmalloc (c * sizeof (CGGlyph));
1440   return self;
1443 - (void) dealloc
1445   if (attrStr != nil)
1446     [attrStr release];
1447   [dict release];
1448   xfree (cglyphs);
1449   [super dealloc];
1452 - (void) setString: (NSString *)str font: (NSFont *)font
1454   [dict setObject: font forKey: NSFontAttributeName];
1455   if (attrStr != nil)
1456     [attrStr release];
1457   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1458   maxChar = [str length];
1459   maxGlyph = 0;
1462 /* NSGlyphStorage protocol */
1463 - (NSUInteger)layoutOptions
1465   return 0;
1468 - (NSAttributedString *)attributedString
1470   return attrStr;
1473 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1474         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1475         characterIndex: (NSUInteger)charIndex
1477   len = glyphIndex+length;
1478   for (i =glyphIndex; i<len; i++)
1479     cglyphs[i] = glyphs[i-glyphIndex];
1480   if (len > maxGlyph)
1481     maxGlyph = len;
1484 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1485         forGlyphAtIndex: (NSUInteger)glyphIndex
1487   return;
1490 @end
1491 #endif /* NS_IMPL_COCOA */
1494 /* Debugging */
1495 void
1496 ns_dump_glyphstring (struct glyph_string *s)
1498   int i;
1500   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1501 "overlap = %d, bg_filled = %d:",
1502            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1503            s->row->overlapping_p, s->background_filled_p);
1504   for (i =0; i<s->nchars; i++)
1505     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1506   fprintf (stderr, "\n");
1510 void
1511 syms_of_nsfont (void)
1513   nsfont_driver.type = Qns;
1514   register_font_driver (&nsfont_driver, NULL);
1515   DEFSYM (Qcondensed, "condensed");
1516   DEFSYM (Qexpanded, "expanded");
1517   DEFSYM (Qapple, "apple");
1518   DEFSYM (Qroman, "roman");
1519   DEFSYM (Qmedium, "medium");
1520   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1521                doc: /* Internal use: maps font registry to Unicode script. */);
1523   ascii_printable = NULL;