Fix "C-x =" wrt display of strong RTL characters and directional controls.
[emacs.git] / src / nsfont.m
blob7d691ced6e1fa402a7a11d0a8f3d2faef5f31dca
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006-2011 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>
26 #include <setjmp.h>
28 #include "lisp.h"
29 #include "dispextern.h"
30 #include "composite.h"
31 #include "blockinput.h"
32 #include "charset.h"
33 #include "frame.h"
34 #include "window.h"
35 #include "fontset.h"
36 #include "nsterm.h"
37 #include "frame.h"
38 #include "character.h"
39 #include "font.h"
40 #include "termchar.h"
42 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
43 #ifdef NS_IMPL_GNUSTEP
44 #import <AppKit/NSFontDescriptor.h>
45 #endif
47 #define NSFONT_TRACE 0
49 extern Lisp_Object Qns;
50 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
51 static Lisp_Object Qapple, Qroman, Qmedium;
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;
57 /* font glyph and metrics caching functions, implemented at end */
58 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
59                               unsigned char block);
60 static void ns_glyph_metrics (struct nsfont_info *font_info,
61                               unsigned char block);
64 /* ==========================================================================
66     Utilities
68    ========================================================================== */
71 /* Replace spaces w/another character so emacs core font parsing routines
72    aren't thrown off. */
73 static void
74 ns_escape_name (char *name)
76   int i =0, len =strlen (name);
77   for ( ; i<len; i++)
78     if (name[i] == ' ')
79       name[i] = '_';
83 /* Reconstruct spaces in a font family name passed through emacs. */
84 static void
85 ns_unescape_name (char *name)
87   int i =0, len =strlen (name);
88   for ( ; i<len; i++)
89     if (name[i] == '_')
90       name[i] = ' ';
94 /* Extract family name from a font spec. */
95 static NSString *
96 ns_get_family (Lisp_Object font_spec)
98   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
99   if (NILP (tem))
100       return nil;
101   else
102     {
103       char *tmp = xstrdup (SDATA (SYMBOL_NAME (tem)));
104       NSString *family;
105       ns_unescape_name (tmp);
106       family = [NSString stringWithUTF8String: tmp];
107       xfree (tmp);
108       return family;
109     }
113 /* Return 0 if attr not set, else value (which might also be 0).
114    On Leopard 0 gets returned even on descriptors where the attribute
115    was never set, so there's no way to distinguish between unspecified
116    and set to not have.  Callers should assume 0 means unspecified. */
117 static float
118 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
120     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
121     NSNumber *val = [tdict objectForKey: trait];
122     return val == nil ? 0.0 : [val floatValue];
126 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
127    to NSFont descriptor.  Information under extra only needed for matching. */
128 #define STYLE_REF 100
129 static NSFontDescriptor
130 *ns_spec_to_descriptor(Lisp_Object font_spec)
132     NSFontDescriptor *fdesc;
133     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
134     NSMutableDictionary *tdict = [NSMutableDictionary new];
135     NSString *family = ns_get_family (font_spec);
136     float n;
138     /* add each attr in font_spec to fdAttrs.. */
139     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
140     if (n != -1 && n != STYLE_REF)
141         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
142                   forKey: NSFontWeightTrait];
143     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
144     if (n != -1 && n != STYLE_REF)
145         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
146                   forKey: NSFontSlantTrait];
147     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
148     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
149         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
150                   forKey: NSFontWidthTrait];
151     if ([tdict count] > 0)
152         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
154     fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
155     if (family != nil)
156         fdesc = [fdesc fontDescriptorWithFamily: family];
157     return fdesc;
161 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
162 static Lisp_Object
163 ns_descriptor_to_entity (NSFontDescriptor *desc,
164                          Lisp_Object extra,
165                          const char *style)
167     Lisp_Object font_entity = font_make_entity ();
168     /*   NSString *psName = [desc postscriptName]; */
169     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
170     unsigned int traits = [desc symbolicTraits];
171     char *escapedFamily;
173     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
174     if (family == nil)
175       family = [desc objectForKey: NSFontNameAttribute];
176     if (family == nil)
177       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
179     escapedFamily = xstrdup ([family UTF8String]);
180     ns_escape_name (escapedFamily);
182     ASET (font_entity, FONT_TYPE_INDEX, Qns);
183     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
184     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
185     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
186     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
188     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
189                     traits & NSFontBoldTrait ? Qbold : Qmedium);
190 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
191                     make_number (100 + 100
192                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
193     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
194                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
195 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
196                     make_number (100 + 100
197                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
198     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
199                     traits & NSFontCondensedTrait ? Qcondensed :
200                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
201 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
202                     make_number (100 + 100
203                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
205     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
206     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
207     ASET (font_entity, FONT_SPACING_INDEX,
208           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
209               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
211     ASET (font_entity, FONT_EXTRA_INDEX, extra);
212     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
214     if (NSFONT_TRACE)
215       {
216         fprintf (stderr, "created font_entity:\n    ");
217         debug_print (font_entity);
218       }
220     xfree (escapedFamily);
221     return font_entity;
225 /* Default font entity. */
226 static Lisp_Object
227 ns_fallback_entity (void)
229   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
230       fontDescriptor], Qnil, NULL);
234 /* Utility: get width of a char c in screen font sfont */
235 static float
236 ns_char_width (NSFont *sfont, int c)
238     float w;
239     NSString *cstr = [NSString stringWithFormat: @"%c", c];
240 #ifdef NS_IMPL_COCOA
241     NSGlyph glyph = [sfont glyphWithName: cstr];
242     if (glyph)
243       {
244         float w = [sfont advancementForGlyph: glyph].width;
245         if (w >= 1.5)
246             return w;
247       }
248 #endif
249     {
250       NSDictionary *attrsDictionary =
251         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
252       w = [cstr sizeWithAttributes: attrsDictionary].width;
253     }
254     return max (w, 2.0);
258 /* Return whether set1 covers set2 to a reasonable extent given by pct.
259    We check, out of each 16 Unicode char range containing chars in set2,
260    whether at least one character is present in set1.
261    This must be true for pct of the pairs to consider it covering. */
262 static BOOL
263 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
265     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
266     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
267     int i, off = 0, tot = 0;
269     for (i=0; i<4096; i++, bytes1++, bytes2++)
270         if (*bytes2)
271           {
272             tot++;
273             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
274                 off++;
275           }
276 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
277     return (float)off / tot < 1.0 - pct;
281 /* Convert :lang property to a script.  Use of :lang property by font backend
282    seems to be limited for now (2009/05) to ja, zh, and ko. */
283 static NSString
284 *ns_lang_to_script (Lisp_Object lang)
286     if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
287         return @"han";
288     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
289              have more characters. */
290     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
291         return @"han";
292     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
293         return @"hangul";
294     else
295         return @"";
299 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
300    everyone just use some standard Unicode names for these?) */
301 static NSString
302 *ns_otf_to_script (Lisp_Object otf)
304     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
305     return CONSP (script)
306         ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (XCDR ((script))))]
307         : @"";
311 /* Convert a font registry, such as  */
312 static NSString
313 *ns_registry_to_script (char *reg)
315     Lisp_Object script, r, rts = Vns_reg_to_script;
316     while CONSP (rts)
317       {
318         r = XCAR (XCAR (rts));
319         if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
320           {
321             script = XCDR (XCAR (rts));
322             return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
323           }
324         rts = XCDR (rts);
325       }
326     return  @"";
330 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
331    plus registry regular property, for something that can be mapped to a
332    Unicode script.  Empty string returned if no script spec found. */
333 static NSString
334 *ns_get_req_script (Lisp_Object font_spec)
336     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
337     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
339     /* The extra-bundle properties have priority. */
340     for ( ; CONSP (extra); extra = XCDR (extra))
341       {
342         Lisp_Object tmp = XCAR (extra);
343         if (CONSP (tmp))
344           {
345             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
346             if (EQ (key, QCscript) && SYMBOLP (val))
347                 return [NSString stringWithUTF8String:
348                             SDATA (SYMBOL_NAME (val))];
349             if (EQ (key, QClang) && SYMBOLP (val))
350                 return ns_lang_to_script (val);
351             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
352                 return ns_otf_to_script (val);
353           }
354       }
356     /* If we get here, check the charset portion of the registry. */
357     if (! NILP (reg))
358       {
359         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
360            (which causes box rendering if we don't treat it like iso8858-1)
361            but also for ascii (which causes unnecessary font substitution). */
362 #if 0
363         if (EQ (reg, Qiso10646_1))
364           reg = Qiso8859_1;
365 #endif
366         return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
367       }
369     return @"";
373 /* This small function is static in fontset.c.  If it can be made public for
374    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
375 static void
376 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
378     if (EQ (XCAR (arg), val))
379       {
380         if (CONSP (range))
381           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
382         else
383           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
384       }
388 /* Use the Unicode range information in Vchar_script_table to convert a script
389    name into an NSCharacterSet. */
390 static NSCharacterSet
391 *ns_script_to_charset (NSString *scriptName)
393     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
394     Lisp_Object script = intern ([scriptName UTF8String]);
395     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
397     if (! NILP (Fmemq (script, script_list)))
398       {
399         Lisp_Object ranges, range_list;
401         ranges = Fcons (script, Qnil);
402         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
403                         ranges);
404         range_list = Fnreverse (XCDR (ranges));
405         if (! NILP (range_list))
406           {
407             for (; CONSP (range_list); range_list = XCDR (range_list))
408               {
409                 int start = XINT (XCAR (XCAR (range_list)));
410                 int end = XINT (XCDR (XCAR (range_list)));
411                 if (NSFONT_TRACE)
412                     debug_print (XCAR (range_list));
413                 if (end < 0x10000)
414                     [charset addCharactersInRange:
415                         NSMakeRange (start, end-start)];
416               }
417           }
418       }
419     return charset;
423 /* Return an array of font families containing characters for the given
424    script, for the given coverage criterion, including at least LastResort.
425    Results are cached by script for faster access.
426    If none are found, we reduce the percentage and try again, until 5%.
427    This provides a font with at least some characters if such can be found.
428    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
429    (b) need approximate match as fonts covering full Unicode ranges are rare. */
430 static NSSet
431 *ns_get_covering_families (NSString *script, float pct)
433     static NSMutableDictionary *scriptToFamilies = nil;
434     NSMutableSet *families;
436     if (NSFONT_TRACE)
437         NSLog(@"Request covering families for script: '%@'", script);
439     if (scriptToFamilies == nil)
440         scriptToFamilies = [[NSMutableDictionary alloc] init];
442     if ((families = [scriptToFamilies objectForKey: script]) == nil)
443       {
444         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
445         NSArray *allFamilies = [fontMgr availableFontFamilies];
447         if ([script length] == 0)
448             families = [NSMutableSet setWithArray: allFamilies];
449         else
450           {
451             NSCharacterSet *charset = ns_script_to_charset (script);
452             NSString *family;
453             families = [NSMutableSet setWithCapacity: 10];
454             while (1)
455               {
456                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
457                 while (family = [allFamiliesEnum nextObject])
458                   {
459                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
460                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
461                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
462                     if (fset == nil)
463                       fset = [NSCharacterSet characterSetWithRange:
464                                                NSMakeRange (0, 127)];
465                     if (ns_charset_covers(fset, charset, pct))
466                         [families addObject: family];
467                   }
468                 pct -= 0.2;
469                 if ([families count] > 0 || pct < 0.05)
470                     break;
471               }
472           }
473 #ifdef NS_IMPL_COCOA
474         if ([families count] == 0)
475             [families addObject: @"LastResort"];
476 #endif
477         [scriptToFamilies setObject: families forKey: script];
478       }
480     if (NSFONT_TRACE)
481         NSLog(@"    returning %d families", [families count]);
482     return families;
486 /* Implementation for list() and match().  List() can return nil, match()
487 must return something.  Strategy is to drop family name from attribute
488 matching set for match. */
489 static Lisp_Object
490 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
492     Lisp_Object tem, list = Qnil;
493     NSFontDescriptor *fdesc, *desc;
494     NSMutableSet *fkeys;
495     NSArray *matchingDescs;
496     NSEnumerator *dEnum;
497     NSString *family;
498     NSSet *cFamilies;
499     BOOL foundItal = NO;
501     if (NSFONT_TRACE)
502       {
503         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
504                  (isMatch ? "match" : "list"));
505         debug_print (font_spec);
506       }
508     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
510     fdesc = ns_spec_to_descriptor (font_spec);
511     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
512     if (isMatch)
513         [fkeys removeObject: NSFontFamilyAttribute];
515     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
516     if (NSFONT_TRACE)
517         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
518               [matchingDescs count]);
520     for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
521       {
522         if (![cFamilies containsObject:
523                  [desc objectForKey: NSFontFamilyAttribute]])
524             continue;
525         tem = ns_descriptor_to_entity (desc,
526                                          AREF (font_spec, FONT_EXTRA_INDEX),
527                                        NULL);
528         if (isMatch)
529           return tem;
530         list = Fcons (tem, list);
531         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
532             foundItal = YES;
533       }
535     /* Add synthItal member if needed. */
536     family = [fdesc objectForKey: NSFontFamilyAttribute];
537     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
538       {
539         NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
540             fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
541             fontDescriptorWithFamily: family];
542         list = Fcons (ns_descriptor_to_entity (sDesc,
543                                          AREF (font_spec, FONT_EXTRA_INDEX),
544                                          "synthItal"), list);
545       }
547     /* Return something if was a match and nothing found. */
548     if (isMatch)
549       return ns_fallback_entity ();
551     if (NSFONT_TRACE)
552         fprintf (stderr, "    Returning %ld entities.\n",
553                  (long) XINT (Flength (list)));
555     return list;
560 /* ==========================================================================
562     Font driver implementation
564    ========================================================================== */
567 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
568 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
569 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
570 static Lisp_Object nsfont_list_family (Lisp_Object frame);
571 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
572                                  int pixel_size);
573 static void nsfont_close (FRAME_PTR f, struct font *font);
574 static int nsfont_has_char (Lisp_Object entity, int c);
575 static unsigned int nsfont_encode_char (struct font *font, int c);
576 static int nsfont_text_extents (struct font *font, unsigned int *code,
577                                 int nglyphs, struct font_metrics *metrics);
578 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
579                         int with_background);
581 struct font_driver nsfont_driver =
582   {
583     0,                          /* Qns */
584     1,                          /* case sensitive */
585     nsfont_get_cache,
586     nsfont_list,
587     nsfont_match,
588     nsfont_list_family,
589     NULL,                       /*free_entity */
590     nsfont_open,
591     nsfont_close,
592     NULL,                       /* prepare_face */
593     NULL,                       /* done_face */
594     nsfont_has_char,
595     nsfont_encode_char,
596     nsfont_text_extents,
597     nsfont_draw,
598     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
599                  anchor_point, otf_capability, otf_driver,
600                  start_for_frame, end_for_frame, shape */
601   };
604 /* Return a cache of font-entities on FRAME.  The cache must be a
605    cons whose cdr part is the actual cache area.  */
606 static Lisp_Object
607 nsfont_get_cache (FRAME_PTR frame)
609   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
610   return (dpyinfo->name_list_element);
614 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
615    **list** of font-entities.  This and match () are sole APIs that allocate
616    font-entities.  Properties to be considered (2009/05/19) are:
617    regular: foundry, family, adstyle, registry
618    extended: script, lang, otf
619   "Extended" properties are not part of the vector but get stored as
620    lisp properties under FONT_EXTRA_INDEX.
622    The returned entities should have type set (to 'ns), plus the following:
623    foundry, family, adstyle, registry,
624    weight, slant, width, size (0 if scalable),
625    dpi, spacing, avgwidth (0 if scalable)  */
626 static Lisp_Object
627 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
629     return ns_findfonts (font_spec, NO);
633 /* Return a font entity most closely maching with FONT_SPEC on
634    FRAME.  The closeness is determined by the font backend, thus
635    `face-font-selection-order' is ignored here.
636    Properties to be considered are same as for list(). */
637 static Lisp_Object
638 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
640     return ns_findfonts(font_spec, YES);
644 /* List available families.  The value is a list of family names
645    (symbols). */
646 static Lisp_Object
647 nsfont_list_family (Lisp_Object frame)
649   Lisp_Object list = Qnil;
650   NSEnumerator *families =
651     [[[NSFontManager sharedFontManager] availableFontFamilies]
652       objectEnumerator];
653   NSString *family;
654   while (family = [families nextObject])
655       list = Fcons (intern ([family UTF8String]), list);
656   /* FIXME: escape the name? */
658   if (NSFONT_TRACE)
659     fprintf (stderr, "nsfont: list families returning %ld entries\n",
660             (long) XINT (Flength (list)));
662   return list;
666 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
667    scalable, open it with PIXEL_SIZE.  */
668 static Lisp_Object
669 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
671   BOOL synthItal;
672   unsigned int traits = 0;
673   struct nsfont_info *font_info;
674   struct font *font;
675   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
676   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
677   NSString *family;
678   NSFont *nsfont, *sfont;
679   Lisp_Object tem;
680   NSRect brect;
681   Lisp_Object font_object;
682   int i;
683   int fixLeopardBug;
684   static NSMutableDictionary *fontCache = nil;
685   NSNumber *cached;
687   /* 2008/03/08: The same font may end up being requested for different
688      entities, due to small differences in numeric values or other issues,
689      or for different copies of the same entity.  Therefore we cache to
690      avoid creating multiple struct font objects (with metrics cache, etc.)
691      for the same NSFont object. */
692   if (fontCache == nil)
693     fontCache = [[NSMutableDictionary alloc] init];
695   if (NSFONT_TRACE)
696     {
697       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
698       debug_print (font_entity);
699     }
701   if (pixel_size <= 0)
702     {
703       /* try to get it out of frame params */
704         Lisp_Object tem = get_frame_param (f, Qfontsize);
705         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
706     }
708   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
709   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
710                                        9);
711   family = ns_get_family (font_entity);
712   if (family == nil)
713     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
714   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
715      when setting family in ns_spec_to_descriptor(). */
716   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
717       traits |= NSBoldFontMask;
718   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
719       traits |= NSItalicFontMask;
721   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
722   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
723   nsfont = [fontMgr fontWithFamily: family
724                             traits: traits weight: fixLeopardBug
725                               size: pixel_size];
726   /* if didn't find, try synthetic italic */
727   if (nsfont == nil && synthItal)
728     {
729       nsfont = [fontMgr fontWithFamily: family
730                                 traits: traits & ~NSItalicFontMask
731                                 weight: fixLeopardBug size: pixel_size];
732     }
733 #ifdef NS_IMPL_COCOA
734   /* LastResort not really a family */
735   if (nsfont == nil && [@"LastResort" isEqualToString: family])
736       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
737 #endif
739   if (nsfont == nil)
740     {
741       message_with_string ("*** Warning: font in family '%s' not found",
742                           build_string ([family UTF8String]), 1);
743       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
744     }
746   if (NSFONT_TRACE)
747     NSLog (@"%@\n", nsfont);
749   /* Check the cache */
750   cached = [fontCache objectForKey: nsfont];
751   if (cached != nil && !synthItal)
752     {
753       if (NSFONT_TRACE)
754         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
755       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
756       XHASH (font_object) = [cached unsignedLongValue];
757       return font_object;
758     }
759   else
760     {
761       font_object = font_make_object (VECSIZE (struct nsfont_info),
762                                       font_entity, pixel_size);
763       if (!synthItal)
764         [fontCache setObject: [NSNumber numberWithUnsignedLong:
765                                           (unsigned long) XHASH (font_object)]
766                       forKey: nsfont];
767     }
769   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
770   font = (struct font *) font_info;
771   if (!font)
772     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
774   font_info->glyphs = (unsigned short **)
775     xmalloc (0x100 * sizeof (unsigned short *));
776   font_info->metrics = (struct font_metrics **)
777     xmalloc (0x100 * sizeof (struct font_metrics *));
778   if (!font_info->glyphs || !font_info->metrics)
779     return Qnil;
780   memset (font_info->glyphs, 0, 0x100 * sizeof (unsigned short *));
781   memset (font_info->metrics, 0, 0x100 * sizeof (struct font_metrics *));
783   BLOCK_INPUT;
785   /* for metrics */
786   sfont = [nsfont screenFont];
787   if (sfont == nil)
788     sfont = nsfont;
790   /* non-metric backend font struct fields */
791   font = (struct font *) font_info;
792   font->pixel_size = [sfont pointSize];
793   font->driver = &nsfont_driver;
794   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
795   font->encoding_charset = -1;
796   font->repertory_charset = -1;
797   font->default_ascent = 0;
798   font->vertical_centering = 0;
799   font->baseline_offset = 0;
800   font->relative_compose = 0;
801   font->font_encoder = NULL;
803   font->props[FONT_FORMAT_INDEX] = Qns;
804   font->props[FONT_FILE_INDEX] = Qnil;
806   {
807     const char *fontName = [[nsfont fontName] UTF8String];
808     int len = strlen (fontName);
810     /* The values specified by fonts are not always exact. For
811      * example, a 6x8 font could specify that the descender is
812      * -2.00000405... (represented by 0xc000000220000000).  Without
813      * adjustment, the code below would round the descender to -3,
814      * resulting in a font that would be one pixel higher than
815      * intended. */
816     CGFloat adjusted_descender = [sfont descender] + 0.0001;
818 #ifdef NS_IMPL_GNUSTEP
819     font_info->nsfont = sfont;
820 #else
821     font_info->nsfont = nsfont;
822 #endif
823     [font_info->nsfont retain];
825     /* set up ns_font (defined in nsgui.h) */
826     font_info->name = (char *)xmalloc (strlen (fontName)+1);
827     strcpy (font_info->name, fontName);
828     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
829     font_info->ital =
830       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
832     /* Metrics etc.; some fonts return an unusually large max advance, so we
833        only use it for fonts that have wide characters. */
834     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
835       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
837     brect =  [sfont boundingRectForFont];
839     font_info->underpos = [sfont underlinePosition];
840     font_info->underwidth = [sfont underlineThickness];
841     font_info->size = font->pixel_size;
843     /* max bounds */
844     font_info->max_bounds.ascent = lrint ([sfont ascender]);
845     /* Descender is usually negative.  Use floor to avoid
846        clipping descenders. */
847     font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
848     font_info->height =
849       font_info->max_bounds.ascent + font_info->max_bounds.descent;
850     font_info->max_bounds.width = lrint (font_info->width);
851     font_info->max_bounds.lbearing = lrint (brect.origin.x);
852     font_info->max_bounds.rbearing =
853       lrint (brect.size.width - font_info->width);
855 #ifdef NS_IMPL_COCOA
856     /* set up synthItal and the CG font */
857     font_info->synthItal = synthItal;
858     {
859       ATSFontRef atsFont = ATSFontFindFromPostScriptName
860         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
862       if (atsFont == kATSFontRefUnspecified)
863         {
864           /* see if we can get it by dropping italic (then synthesizing) */
865           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
866               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
867                 fontName], kATSOptionFlagsDefault);
868           if (atsFont != kATSFontRefUnspecified)
869               font_info->synthItal = YES;
870           else
871             {
872               /* last resort fallback */
873               atsFont = ATSFontFindFromPostScriptName
874                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
875             }
876         }
877       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
878     }
879 #endif
881     /* set up metrics portion of font struct */
882     font->ascent = lrint([sfont ascender]);
883     font->descent = -lrint(floor(adjusted_descender));
884     font->min_width = ns_char_width(sfont, '|');
885     font->space_width = lrint (ns_char_width (sfont, ' '));
886     font->average_width = lrint (font_info->width);
887     font->max_width = lrint (font_info->max_bounds.width);
888     font->height = lrint (font_info->height);
889     font->underline_position = lrint (font_info->underpos);
890     font->underline_thickness = lrint (font_info->underwidth);
892     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
893     font->props[FONT_FULLNAME_INDEX] =
894       make_unibyte_string (font_info->name, strlen (font_info->name));
895   }
896   UNBLOCK_INPUT;
898   return font_object;
902 /* Close FONT on frame F. */
903 static void
904 nsfont_close (FRAME_PTR f, struct font *font)
906   struct nsfont_info *font_info = (struct nsfont_info *)font;
907   int i;
909   /* FIXME: this occurs apparently due to same failure to detect same font
910             that causes need for cache in nsfont_open () */
911   if (!font_info)
912       return;
914   for (i =0; i<0x100; i++)
915     {
916       xfree (font_info->glyphs[i]);
917       xfree (font_info->metrics[i]);
918     }
919   [font_info->nsfont release];
920 #ifdef NS_IMPL_COCOA
921   CGFontRelease (font_info->cgfont);
922 #endif
923   xfree (font_info->name);
924   xfree (font_info);
928 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
929    return 1.  If not, return 0.  If a font must be opened to check
930    it, return -1. */
931 static int
932 nsfont_has_char (Lisp_Object entity, int c)
934   return -1;
938 /* Return a glyph code of FONT for character C (Unicode code point).
939    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
940 static unsigned int
941 nsfont_encode_char (struct font *font, int c)
943   struct nsfont_info *font_info = (struct nsfont_info *)font;
944   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
945   unsigned short g;
947   if (c > 0xFFFF)
948     return FONT_INVALID_CODE;
950   /* did we already cache this block? */
951   if (!font_info->glyphs[high])
952     ns_uni_to_glyphs (font_info, high);
954   g = font_info->glyphs[high][low];
955   return g == 0xFFFF ? FONT_INVALID_CODE : g;
959 /* Perform the size computation of glyphs of FONT and fill in members
960    of METRICS.  The glyphs are specified by their glyph codes in
961    CODE (length NGLYPHS). */
962 static int
963 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
964                      struct font_metrics *metrics)
966   struct nsfont_info *font_info = (struct nsfont_info *)font;
967   struct font_metrics *pcm;
968   unsigned char high, low;
969   int totalWidth = 0;
970   int i;
972   memset (metrics, 0, sizeof (struct font_metrics));
974   for (i =0; i<nglyphs; i++)
975     {
976       /* get metrics for this glyph, filling cache if need be */
977       /* TODO: get metrics for whole string from an NSLayoutManager
978                (if not too slow) */
979       high = (code[i] & 0xFF00) >> 8;
980       low = code[i] & 0x00FF;
981       if (!font_info->metrics[high])
982         ns_glyph_metrics (font_info, high);
983       pcm = &(font_info->metrics[high][low]);
985       if (metrics->lbearing > totalWidth + pcm->lbearing)
986         metrics->lbearing = totalWidth + pcm->lbearing;
987       if (metrics->rbearing < totalWidth + pcm->rbearing)
988         metrics->rbearing = totalWidth + pcm->rbearing;
989       if (metrics->ascent < pcm->ascent)
990         metrics->ascent = pcm->ascent;
991       if (metrics->descent < pcm->descent)
992         metrics->descent = pcm->descent;
994       totalWidth += pcm->width;
995     }
997   metrics->width = totalWidth;
999   return totalWidth; /* not specified in doc, but xfont.c does it */
1003 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1004    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
1005    is nonzero, fill the background in advance.  It is assured that
1006    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1007 static int
1008 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1009              int with_background)
1010 /* NOTE: focus and clip must be set
1011      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1013   static char cbuf[1024];
1014   char *c = cbuf;
1015 #ifdef NS_IMPL_GNUSTEP
1016   static float advances[1024];
1017   float *adv = advances;
1018 #else
1019   static CGSize advances[1024];
1020   CGSize *adv = advances;
1021 #endif
1022   struct face *face;
1023   NSRect r;
1024   struct nsfont_info *font = ns_tmp_font;
1025   NSColor *col, *bgCol;
1026   unsigned short *t = s->char2b;
1027   int i, len;
1028   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1029   int end = isComposite ? s->cmp_to : s->nchars;
1031   /* Select face based on input flags */
1032   switch (ns_tmp_flags)
1033     {
1034     case NS_DUMPGLYPH_CURSOR:
1035       face = s->face;
1036       break;
1037     case NS_DUMPGLYPH_MOUSEFACE:
1038       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1039       if (!face)
1040         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1041       break;
1042     default:
1043       face = s->face;
1044     }
1046   r.origin.x = s->x;
1047   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1048     r.origin.x += abs (s->face->box_line_width);
1050   r.origin.y = s->y;
1051   r.size.height = FONT_HEIGHT (font);
1053   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1054      NS to render the string, it will come out differently from the individual
1055      character widths added up because of layout processing. */
1056   {
1057     XCharStruct *cs;
1058     int cwidth, twidth = 0;
1059     int hi, lo;
1060     /* FIXME: composition: no vertical displacement is considered. */
1061     t += s->cmp_from; /* advance into composition */
1062     for (i = s->cmp_from; i < end; i++, t++)
1063       {
1064         hi = (*t & 0xFF00) >> 8;
1065         lo = *t & 0x00FF;
1066         if (isComposite)
1067           {
1068             if (!s->first_glyph->u.cmp.automatic)
1069                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1070             else
1071               {
1072                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1073                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1074                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1075                     cwidth = LGLYPH_WIDTH (glyph);
1076                 else
1077                   {
1078                     cwidth = LGLYPH_WADJUST (glyph);
1079 #ifdef NS_IMPL_GNUSTEP
1080                     *(adv-1) += LGLYPH_XOFF (glyph);
1081 #else
1082                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1083 #endif
1084                   }
1085               }
1086           }
1087         else
1088           {
1089             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1090               ns_glyph_metrics (font, hi);
1091             cwidth = font->metrics[hi][lo].width;
1092           }
1093         twidth += cwidth;
1094 #ifdef NS_IMPL_GNUSTEP
1095         *adv++ = cwidth;
1096         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1097 #else
1098         (*adv++).width = cwidth;
1099 #endif
1100       }
1101     len = adv - advances;
1102     r.size.width = twidth;
1103     *c = 0;
1104   }
1106   /* fill background if requested */
1107   if (with_background && !isComposite)
1108     {
1109       NSRect br = r;
1110       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1111       int mbox_line_width = max (s->face->box_line_width, 0);
1113       if (s->row->full_width_p)
1114         {
1115           if (br.origin.x <= fibw + 1 + mbox_line_width)
1116             {
1117               br.size.width += br.origin.x - mbox_line_width;
1118               br.origin.x = mbox_line_width;
1119             }
1120           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1121                 <= fibw+1)
1122             br.size.width += fibw;
1123         }
1124       if (s->face->box == FACE_NO_BOX)
1125         {
1126           /* expand unboxed top row over internal border */
1127           if (br.origin.y <= fibw + 1 + mbox_line_width)
1128             {
1129               br.size.height += br.origin.y;
1130               br.origin.y = 0;
1131             }
1132         }
1133       else
1134         {
1135           int correction = abs (s->face->box_line_width)+1;
1136           br.origin.y += correction;
1137           br.size.height -= 2*correction;
1138           br.origin.x += correction;
1139           br.size.width -= 2*correction;
1140         }
1142       if (!s->face->stipple)
1143         [(NS_FACE_BACKGROUND (face) != 0
1144           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1145           : FRAME_BACKGROUND_COLOR (s->f)) set];
1146       else
1147         {
1148           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1149           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1150         }
1151       NSRectFill (br);
1152     }
1155   /* set up for character rendering */
1156   r.origin.y = s->ybase;
1158   col = (NS_FACE_FOREGROUND (face) != 0
1159          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1160          : FRAME_FOREGROUND_COLOR (s->f));
1161   /* FIXME: find another way to pass this */
1162   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1163            : (NS_FACE_BACKGROUND (face) != 0
1164               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1165               : FRAME_BACKGROUND_COLOR (s->f)));
1167   /* render under GNUstep using DPS */
1168 #ifdef NS_IMPL_GNUSTEP
1169   {
1170     NSGraphicsContext *context = GSCurrentContext ();
1172     DPSgsave (context);
1173     [font->nsfont set];
1175     /* do erase if "foreground" mode */
1176     if (bgCol != nil)
1177       {
1178         [bgCol set];
1179         DPSmoveto (context, r.origin.x, r.origin.y);
1180 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1181         DPSxshow (context, cbuf, advances, len);
1182         DPSstroke (context);
1183         [col set];
1184 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1185       }
1187     [col set];
1189     /* draw with DPSxshow () */
1190     DPSmoveto (context, r.origin.x, r.origin.y);
1191     DPSxshow (context, cbuf, advances, len);
1192     DPSstroke (context);
1194     DPSgrestore (context);
1195   }
1197 #else  /* NS_IMPL_COCOA */
1198   {
1199     CGContextRef gcontext =
1200       [[NSGraphicsContext currentContext] graphicsPort];
1201     static CGAffineTransform fliptf;
1202     static BOOL firstTime = YES;
1204     if (firstTime)
1205       {
1206         firstTime = NO;
1207         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1208       }
1210     CGContextSaveGState (gcontext);
1212     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1214     CGContextSetFont (gcontext, font->cgfont);
1215     CGContextSetFontSize (gcontext, font->size);
1216     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1217       CGContextSetShouldAntialias (gcontext, 0);
1218     else
1219       CGContextSetShouldAntialias (gcontext, 1);
1221     CGContextSetTextMatrix (gcontext, fliptf);
1223     if (bgCol != nil)
1224       {
1225         /* foreground drawing; erase first to avoid overstrike */
1226         [bgCol set];
1227         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1228         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1229         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1230         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1231       }
1233     [col set];
1235     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1236     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1237                                     advances, len);
1239     if (face->overstrike)
1240       {
1241         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1242         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1243                                         advances, len);
1244       }
1246     CGContextRestoreGState (gcontext);
1247   }
1248 #endif  /* NS_IMPL_COCOA */
1250   /* Draw underline, overline, strike-through. */
1251   ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1253   return to-from;
1258 /* ==========================================================================
1260     Font glyph and metrics caching functions
1262    ========================================================================== */
1264 /* Find and cache corresponding glyph codes for unicode values in given
1265    hi-byte block of 256. */
1266 static void
1267 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1269 #ifdef NS_IMPL_COCOA
1270   static EmacsGlyphStorage *glyphStorage;
1271   static char firstTime = 1;
1272 #endif
1273   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1274   unsigned int i, g, idx;
1275   unsigned short *glyphs;
1277   if (NSFONT_TRACE)
1278     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1279             font_info, block);
1281  BLOCK_INPUT;
1283 #ifdef NS_IMPL_COCOA
1284   if (firstTime)
1285     {
1286       firstTime = 0;
1287       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1288     }
1289 #endif
1291   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1292   if (!unichars || !(font_info->glyphs[block]))
1293     abort ();
1295   /* create a string containing all Unicode characters in this block */
1296   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1297     if (idx < 0xD800 || idx > 0xDFFF)
1298       unichars[i] = idx;
1299     else
1300       unichars[i] = 0xFEFF;
1301   unichars[0x100] = 0;
1303   {
1304 #ifdef NS_IMPL_COCOA
1305     NSString *allChars = [[NSString alloc]
1306                                initWithCharactersNoCopy: unichars
1307                                                  length: 0x100
1308                                            freeWhenDone: NO];
1309     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1310     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1311     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1312     NSUInteger gInd =0, cInd =0;
1314     [glyphStorage setString: allChars font: font_info->nsfont];
1315     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1316                         desiredNumberOfCharacters: glyphStorage->maxChar
1317                                        glyphIndex: &gInd characterIndex: &cInd];
1318 #endif
1319     glyphs = font_info->glyphs[block];
1320     for (i =0; i<0x100; i++, glyphs++)
1321       {
1322 #ifdef NS_IMPL_GNUSTEP
1323         g = unichars[i];
1324 #else
1325         g = glyphStorage->cglyphs[i];
1326         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1327         if (g > numGlyphs)
1328           g = 0xFFFF; /* hopefully unused... */
1329 #endif
1330         *glyphs = g;
1331       }
1333 #ifdef NS_IMPL_COCOA
1334     [allChars release];
1335 #endif
1336   }
1338   UNBLOCK_INPUT;
1339   xfree (unichars);
1343 /* Determine and cache metrics for corresponding glyph codes in given
1344    hi-byte block of 256. */
1345 static void
1346 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1348   unsigned int i, g;
1349   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1350   NSFont *sfont;
1351   struct font_metrics *metrics;
1353   if (NSFONT_TRACE)
1354     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1355             font_info, block);
1357 #ifdef NS_IMPL_GNUSTEP
1358   /* not implemented yet (as of startup 0.18), so punt */
1359   if (numGlyphs == 0)
1360     numGlyphs = 0x10000;
1361 #endif
1363  BLOCK_INPUT;
1364  sfont = [font_info->nsfont screenFont];
1366   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1367   memset (font_info->metrics[block], 0, 0x100 * sizeof (struct font_metrics));
1368   if (!(font_info->metrics[block]))
1369     abort ();
1371   metrics = font_info->metrics[block];
1372   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1373     {
1374       float w, lb, rb;
1375       NSRect r = [sfont boundingRectForGlyph: g];
1377       w = max ([sfont advancementForGlyph: g].width, 2.0);
1378       metrics->width = lrint (w);
1380       lb = r.origin.x;
1381       rb = r.size.width - w;
1382       if (lb < 0)
1383         metrics->lbearing = round (lb);
1384       if (font_info->ital)
1385         rb += 0.22 * font_info->height;
1386       metrics->rbearing = lrint (w + rb);
1388       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1389  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1390       metrics->ascent = r.size.height - metrics->descent;
1391 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1392     }
1393   UNBLOCK_INPUT;
1397 #ifdef NS_IMPL_COCOA
1398 /* helper for font glyph setup */
1399 @implementation EmacsGlyphStorage
1401 - init
1403   return [self initWithCapacity: 1024];
1406 - initWithCapacity: (unsigned long) c
1408   self = [super init];
1409   maxChar = 0;
1410   maxGlyph = 0;
1411   dict = [NSMutableDictionary new];
1412   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1413   return self;
1416 - (void) dealloc
1418   if (attrStr != nil)
1419     [attrStr release];
1420   [dict release];
1421   xfree (cglyphs);
1422   [super dealloc];
1425 - (void) setString: (NSString *)str font: (NSFont *)font
1427   [dict setObject: font forKey: NSFontAttributeName];
1428   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1429   maxChar = [str length];
1430   maxGlyph = 0;
1433 /* NSGlyphStorage protocol */
1434 - (NSUInteger)layoutOptions
1436   return 0;
1439 - (NSAttributedString *)attributedString
1441   return attrStr;
1444 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1445         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1446         characterIndex: (NSUInteger)charIndex
1448   len = glyphIndex+length;
1449   for (i =glyphIndex; i<len; i++)
1450     cglyphs[i] = glyphs[i-glyphIndex];
1451   if (len > maxGlyph)
1452     maxGlyph = len;
1455 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1456         forGlyphAtIndex: (NSUInteger)glyphIndex
1458   return;
1461 @end
1462 #endif /* NS_IMPL_COCOA */
1465 /* Debugging */
1466 void
1467 ns_dump_glyphstring (struct glyph_string *s)
1469   int i;
1471   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1472 "overlap = %d, bg_filled = %d:",
1473            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1474            s->row->overlapping_p, s->background_filled_p);
1475   for (i =0; i<s->nchars; i++)
1476     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1477   fprintf (stderr, "\n");
1481 void
1482 syms_of_nsfont (void)
1484   nsfont_driver.type = Qns;
1485   register_font_driver (&nsfont_driver, NULL);
1486   DEFSYM (Qapple, "apple");
1487   DEFSYM (Qroman, "roman");
1488   DEFSYM (Qmedium, "medium");
1489   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1490                doc: /* Internal use: maps font registry to Unicode script. */);