* nsfont.m (ns_charset_covers): Don't abort if no bitmap.
[emacs.git] / src / nsfont.m
blob7a44182a93eac96ed313782f3d249cb7e9ac6457
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006-2012 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       {
157         fdesc = [fdesc fontDescriptorWithFamily: family];
158       }
160     [fdAttrs release];
161     [tdict release];
162     return fdesc;
166 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
167 static Lisp_Object
168 ns_descriptor_to_entity (NSFontDescriptor *desc,
169                          Lisp_Object extra,
170                          const char *style)
172     Lisp_Object font_entity = font_make_entity ();
173     /*   NSString *psName = [desc postscriptName]; */
174     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
175     unsigned int traits = [desc symbolicTraits];
176     char *escapedFamily;
178     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
179     if (family == nil)
180       family = [desc objectForKey: NSFontNameAttribute];
181     if (family == nil)
182       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
184     escapedFamily = xstrdup ([family UTF8String]);
185     ns_escape_name (escapedFamily);
187     ASET (font_entity, FONT_TYPE_INDEX, Qns);
188     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
189     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
190     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
191     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
193     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
194                     traits & NSFontBoldTrait ? Qbold : Qmedium);
195 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
196                     make_number (100 + 100
197                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
198     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
199                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
200 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
201                     make_number (100 + 100
202                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
203     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
204                     traits & NSFontCondensedTrait ? Qcondensed :
205                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
206 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
207                     make_number (100 + 100
208                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
210     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
211     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
212     ASET (font_entity, FONT_SPACING_INDEX,
213           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
214               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
216     ASET (font_entity, FONT_EXTRA_INDEX, extra);
217     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
219     if (NSFONT_TRACE)
220       {
221         fprintf (stderr, "created font_entity:\n    ");
222         debug_print (font_entity);
223       }
225     xfree (escapedFamily);
226     return font_entity;
230 /* Default font entity. */
231 static Lisp_Object
232 ns_fallback_entity (void)
234   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
235       fontDescriptor], Qnil, NULL);
239 /* Utility: get width of a char c in screen font sfont */
240 static float
241 ns_char_width (NSFont *sfont, int c)
243     float w;
244     NSString *cstr = [NSString stringWithFormat: @"%c", c];
245 #ifdef NS_IMPL_COCOA
246     NSGlyph glyph = [sfont glyphWithName: cstr];
247     if (glyph)
248       {
249         float w = [sfont advancementForGlyph: glyph].width;
250         if (w >= 1.5)
251             return w;
252       }
253 #endif
254     {
255       NSDictionary *attrsDictionary =
256         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
257       w = [cstr sizeWithAttributes: attrsDictionary].width;
258     }
259     return max (w, 2.0);
263 /* Return whether set1 covers set2 to a reasonable extent given by pct.
264    We check, out of each 16 Unicode char range containing chars in set2,
265    whether at least one character is present in set1.
266    This must be true for pct of the pairs to consider it covering. */
267 static BOOL
268 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
270     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
271     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
272     int i, off = 0, tot = 0;
274     /* Work around what appears to be a GNUstep bug.
275        See <http://bugs.gnu.org/11853>.  */
276     if (! (bytes1 && bytes2))
277       return NO;
279     for (i=0; i<4096; i++, bytes1++, bytes2++)
280         if (*bytes2)
281           {
282             tot++;
283             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
284                 off++;
285           }
286 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
287     return (float)off / tot < 1.0 - pct;
291 /* Convert :lang property to a script.  Use of :lang property by font backend
292    seems to be limited for now (2009/05) to ja, zh, and ko. */
293 static NSString
294 *ns_lang_to_script (Lisp_Object lang)
296     if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
297         return @"han";
298     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
299              have more characters. */
300     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
301         return @"han";
302     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
303         return @"hangul";
304     else
305         return @"";
309 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
310    everyone just use some standard Unicode names for these?) */
311 static NSString
312 *ns_otf_to_script (Lisp_Object otf)
314     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
315     return CONSP (script)
316         ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (XCDR ((script))))]
317         : @"";
321 /* Convert a font registry, such as  */
322 static NSString
323 *ns_registry_to_script (char *reg)
325     Lisp_Object script, r, rts = Vns_reg_to_script;
326     while CONSP (rts)
327       {
328         r = XCAR (XCAR (rts));
329         if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
330           {
331             script = XCDR (XCAR (rts));
332             return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
333           }
334         rts = XCDR (rts);
335       }
336     return  @"";
340 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
341    plus registry regular property, for something that can be mapped to a
342    Unicode script.  Empty string returned if no script spec found. */
343 static NSString
344 *ns_get_req_script (Lisp_Object font_spec)
346     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
347     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
349     /* The extra-bundle properties have priority. */
350     for ( ; CONSP (extra); extra = XCDR (extra))
351       {
352         Lisp_Object tmp = XCAR (extra);
353         if (CONSP (tmp))
354           {
355             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
356             if (EQ (key, QCscript) && SYMBOLP (val))
357                 return [NSString stringWithUTF8String:
358                             SDATA (SYMBOL_NAME (val))];
359             if (EQ (key, QClang) && SYMBOLP (val))
360                 return ns_lang_to_script (val);
361             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
362                 return ns_otf_to_script (val);
363           }
364       }
366     /* If we get here, check the charset portion of the registry. */
367     if (! NILP (reg))
368       {
369         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
370            (which causes box rendering if we don't treat it like iso8858-1)
371            but also for ascii (which causes unnecessary font substitution). */
372 #if 0
373         if (EQ (reg, Qiso10646_1))
374           reg = Qiso8859_1;
375 #endif
376         return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
377       }
379     return @"";
383 /* This small function is static in fontset.c.  If it can be made public for
384    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
385 static void
386 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
388     if (EQ (XCAR (arg), val))
389       {
390         if (CONSP (range))
391           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
392         else
393           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
394       }
398 /* Use the Unicode range information in Vchar_script_table to convert a script
399    name into an NSCharacterSet. */
400 static NSCharacterSet
401 *ns_script_to_charset (NSString *scriptName)
403     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
404     Lisp_Object script = intern ([scriptName UTF8String]);
405     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
407     if (! NILP (Fmemq (script, script_list)))
408       {
409         Lisp_Object ranges, range_list;
411         ranges = Fcons (script, Qnil);
412         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
413                         ranges);
414         range_list = Fnreverse (XCDR (ranges));
415         if (! NILP (range_list))
416           {
417             for (; CONSP (range_list); range_list = XCDR (range_list))
418               {
419                 int start = XINT (XCAR (XCAR (range_list)));
420                 int end = XINT (XCDR (XCAR (range_list)));
421                 if (NSFONT_TRACE)
422                     debug_print (XCAR (range_list));
423                 if (end < 0x10000)
424                     [charset addCharactersInRange:
425                         NSMakeRange (start, end-start)];
426               }
427           }
428       }
429     return charset;
433 /* Return an array of font families containing characters for the given
434    script, for the given coverage criterion, including at least LastResort.
435    Results are cached by script for faster access.
436    If none are found, we reduce the percentage and try again, until 5%.
437    This provides a font with at least some characters if such can be found.
438    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
439    (b) need approximate match as fonts covering full Unicode ranges are rare. */
440 static NSSet
441 *ns_get_covering_families (NSString *script, float pct)
443     static NSMutableDictionary *scriptToFamilies = nil;
444     NSMutableSet *families;
446     if (NSFONT_TRACE)
447         NSLog(@"Request covering families for script: '%@'", script);
449     if (scriptToFamilies == nil)
450         scriptToFamilies = [[NSMutableDictionary alloc] init];
452     if ((families = [scriptToFamilies objectForKey: script]) == nil)
453       {
454         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
455         NSArray *allFamilies = [fontMgr availableFontFamilies];
457         if ([script length] == 0)
458             families = [NSMutableSet setWithArray: allFamilies];
459         else
460           {
461             NSCharacterSet *charset = ns_script_to_charset (script);
462             NSString *family;
463             families = [NSMutableSet setWithCapacity: 10];
464             while (1)
465               {
466                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
467                 while (family = [allFamiliesEnum nextObject])
468                   {
469                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
470                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
471                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
472                     if (fset == nil)
473                       fset = [NSCharacterSet characterSetWithRange:
474                                                NSMakeRange (0, 127)];
475                     if (ns_charset_covers(fset, charset, pct))
476                         [families addObject: family];
477                   }
478                 pct -= 0.2;
479                 if ([families count] > 0 || pct < 0.05)
480                     break;
481               }
482             [charset release];
483           }
484 #ifdef NS_IMPL_COCOA
485         if ([families count] == 0)
486             [families addObject: @"LastResort"];
487 #endif
488         [scriptToFamilies setObject: families forKey: script];
489       }
491     if (NSFONT_TRACE)
492         NSLog(@"    returning %d families", [families count]);
493     return families;
497 /* Implementation for list() and match().  List() can return nil, match()
498 must return something.  Strategy is to drop family name from attribute
499 matching set for match. */
500 static Lisp_Object
501 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
503     Lisp_Object tem, list = Qnil;
504     NSFontDescriptor *fdesc, *desc;
505     NSMutableSet *fkeys;
506     NSArray *matchingDescs;
507     NSEnumerator *dEnum;
508     NSString *family;
509     NSSet *cFamilies;
510     BOOL foundItal = NO;
512     if (NSFONT_TRACE)
513       {
514         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
515                  (isMatch ? "match" : "list"));
516         debug_print (font_spec);
517       }
519     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
521     fdesc = ns_spec_to_descriptor (font_spec);
522     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
523     if (isMatch)
524         [fkeys removeObject: NSFontFamilyAttribute];
526     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
527     if (NSFONT_TRACE)
528         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
529               [matchingDescs count]);
531     for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
532       {
533         if (![cFamilies containsObject:
534                  [desc objectForKey: NSFontFamilyAttribute]])
535             continue;
536         tem = ns_descriptor_to_entity (desc,
537                                          AREF (font_spec, FONT_EXTRA_INDEX),
538                                        NULL);
539         if (isMatch)
540           return tem;
541         list = Fcons (tem, list);
542         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
543             foundItal = YES;
544       }
546     /* Add synthItal member if needed. */
547     family = [fdesc objectForKey: NSFontFamilyAttribute];
548     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
549       {
550         NSFontDescriptor *s1 = [NSFontDescriptor new];
551         NSFontDescriptor *sDesc
552           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
553               fontDescriptorWithFamily: family];
554         list = Fcons (ns_descriptor_to_entity (sDesc,
555                                          AREF (font_spec, FONT_EXTRA_INDEX),
556                                          "synthItal"), list);
557         [s1 release];
558       }
560     /* Return something if was a match and nothing found. */
561     if (isMatch)
562       return ns_fallback_entity ();
564     if (NSFONT_TRACE)
565         fprintf (stderr, "    Returning %"pI"d entities.\n",
566                  XINT (Flength (list)));
568     return list;
573 /* ==========================================================================
575     Font driver implementation
577    ========================================================================== */
580 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
581 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
582 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
583 static Lisp_Object nsfont_list_family (Lisp_Object frame);
584 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
585                                  int pixel_size);
586 static void nsfont_close (FRAME_PTR f, struct font *font);
587 static int nsfont_has_char (Lisp_Object entity, int c);
588 static unsigned int nsfont_encode_char (struct font *font, int c);
589 static int nsfont_text_extents (struct font *font, unsigned int *code,
590                                 int nglyphs, struct font_metrics *metrics);
591 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
592                         int with_background);
594 struct font_driver nsfont_driver =
595   {
596     0,                          /* Qns */
597     1,                          /* case sensitive */
598     nsfont_get_cache,
599     nsfont_list,
600     nsfont_match,
601     nsfont_list_family,
602     NULL,                       /*free_entity */
603     nsfont_open,
604     nsfont_close,
605     NULL,                       /* prepare_face */
606     NULL,                       /* done_face */
607     nsfont_has_char,
608     nsfont_encode_char,
609     nsfont_text_extents,
610     nsfont_draw,
611     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
612                  anchor_point, otf_capability, otf_driver,
613                  start_for_frame, end_for_frame, shape */
614   };
617 /* Return a cache of font-entities on FRAME.  The cache must be a
618    cons whose cdr part is the actual cache area.  */
619 static Lisp_Object
620 nsfont_get_cache (FRAME_PTR frame)
622   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
623   return (dpyinfo->name_list_element);
627 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
628    **list** of font-entities.  This and match () are sole APIs that allocate
629    font-entities.  Properties to be considered (2009/05/19) are:
630    regular: foundry, family, adstyle, registry
631    extended: script, lang, otf
632   "Extended" properties are not part of the vector but get stored as
633    lisp properties under FONT_EXTRA_INDEX.
635    The returned entities should have type set (to 'ns), plus the following:
636    foundry, family, adstyle, registry,
637    weight, slant, width, size (0 if scalable),
638    dpi, spacing, avgwidth (0 if scalable)  */
639 static Lisp_Object
640 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
642     return ns_findfonts (font_spec, NO);
646 /* Return a font entity most closely matching with FONT_SPEC on
647    FRAME.  The closeness is determined by the font backend, thus
648    `face-font-selection-order' is ignored here.
649    Properties to be considered are same as for list(). */
650 static Lisp_Object
651 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
653     return ns_findfonts(font_spec, YES);
657 /* List available families.  The value is a list of family names
658    (symbols). */
659 static Lisp_Object
660 nsfont_list_family (Lisp_Object frame)
662   Lisp_Object list = Qnil;
663   NSEnumerator *families =
664     [[[NSFontManager sharedFontManager] availableFontFamilies]
665       objectEnumerator];
666   NSString *family;
667   while (family = [families nextObject])
668       list = Fcons (intern ([family UTF8String]), list);
669   /* FIXME: escape the name? */
671   if (NSFONT_TRACE)
672     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
673              XINT (Flength (list)));
675   return list;
679 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
680    scalable, open it with PIXEL_SIZE.  */
681 static Lisp_Object
682 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
684   BOOL synthItal;
685   unsigned int traits = 0;
686   struct nsfont_info *font_info;
687   struct font *font;
688   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
689   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
690   NSString *family;
691   NSFont *nsfont, *sfont;
692   Lisp_Object tem;
693   NSRect brect;
694   Lisp_Object font_object;
695   int i;
696   int fixLeopardBug;
697   static NSMutableDictionary *fontCache = nil;
698   NSNumber *cached;
700   /* 2008/03/08: The same font may end up being requested for different
701      entities, due to small differences in numeric values or other issues,
702      or for different copies of the same entity.  Therefore we cache to
703      avoid creating multiple struct font objects (with metrics cache, etc.)
704      for the same NSFont object. */
705   if (fontCache == nil)
706     fontCache = [[NSMutableDictionary alloc] init];
708   if (NSFONT_TRACE)
709     {
710       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
711       debug_print (font_entity);
712     }
714   if (pixel_size <= 0)
715     {
716       /* try to get it out of frame params */
717         Lisp_Object tem = get_frame_param (f, Qfontsize);
718         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
719     }
721   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
722   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
723                                        9);
724   family = ns_get_family (font_entity);
725   if (family == nil)
726     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
727   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
728      when setting family in ns_spec_to_descriptor(). */
729   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
730       traits |= NSBoldFontMask;
731   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
732       traits |= NSItalicFontMask;
734   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
735   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
736   nsfont = [fontMgr fontWithFamily: family
737                             traits: traits weight: fixLeopardBug
738                               size: pixel_size];
739   /* if didn't find, try synthetic italic */
740   if (nsfont == nil && synthItal)
741     {
742       nsfont = [fontMgr fontWithFamily: family
743                                 traits: traits & ~NSItalicFontMask
744                                 weight: fixLeopardBug size: pixel_size];
745     }
746 #ifdef NS_IMPL_COCOA
747   /* LastResort not really a family */
748   if (nsfont == nil && [@"LastResort" isEqualToString: family])
749       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
750 #endif
752   if (nsfont == nil)
753     {
754       message_with_string ("*** Warning: font in family '%s' not found",
755                           build_string ([family UTF8String]), 1);
756       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
757     }
759   if (NSFONT_TRACE)
760     NSLog (@"%@\n", nsfont);
762   /* Check the cache */
763   cached = [fontCache objectForKey: nsfont];
764   if (cached != nil && !synthItal)
765     {
766       if (NSFONT_TRACE)
767         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
768       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
769       XHASH (font_object) = [cached unsignedLongValue];
770       return font_object;
771     }
772   else
773     {
774       font_object = font_make_object (VECSIZE (struct nsfont_info),
775                                       font_entity, pixel_size);
776       if (!synthItal)
777         [fontCache setObject: [NSNumber numberWithUnsignedLong:
778                                           (unsigned long) XHASH (font_object)]
779                       forKey: nsfont];
780     }
782   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
783   font = (struct font *) font_info;
784   if (!font)
785     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
787   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
788   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
790   BLOCK_INPUT;
792   /* for metrics */
793   sfont = [nsfont screenFont];
794   if (sfont == nil)
795     sfont = nsfont;
797   /* non-metric backend font struct fields */
798   font = (struct font *) font_info;
799   font->pixel_size = [sfont pointSize];
800   font->driver = &nsfont_driver;
801   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
802   font->encoding_charset = -1;
803   font->repertory_charset = -1;
804   font->default_ascent = 0;
805   font->vertical_centering = 0;
806   font->baseline_offset = 0;
807   font->relative_compose = 0;
808   font->font_encoder = NULL;
810   font->props[FONT_FORMAT_INDEX] = Qns;
811   font->props[FONT_FILE_INDEX] = Qnil;
813   {
814     const char *fontName = [[nsfont fontName] UTF8String];
815     int len = strlen (fontName);
817     /* The values specified by fonts are not always exact. For
818      * example, a 6x8 font could specify that the descender is
819      * -2.00000405... (represented by 0xc000000220000000).  Without
820      * adjustment, the code below would round the descender to -3,
821      * resulting in a font that would be one pixel higher than
822      * intended. */
823     CGFloat adjusted_descender = [sfont descender] + 0.0001;
825 #ifdef NS_IMPL_GNUSTEP
826     font_info->nsfont = sfont;
827 #else
828     font_info->nsfont = nsfont;
829 #endif
830     [font_info->nsfont retain];
832     /* set up ns_font (defined in nsgui.h) */
833     font_info->name = xstrdup (fontName);
834     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
835     font_info->ital =
836       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
838     /* Metrics etc.; some fonts return an unusually large max advance, so we
839        only use it for fonts that have wide characters. */
840     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
841       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
843     brect =  [sfont boundingRectForFont];
845     font_info->underpos = [sfont underlinePosition];
846     font_info->underwidth = [sfont underlineThickness];
847     font_info->size = font->pixel_size;
849     /* max bounds */
850     font_info->max_bounds.ascent = lrint ([sfont ascender]);
851     /* Descender is usually negative.  Use floor to avoid
852        clipping descenders. */
853     font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
854     font_info->height =
855       font_info->max_bounds.ascent + font_info->max_bounds.descent;
856     font_info->max_bounds.width = lrint (font_info->width);
857     font_info->max_bounds.lbearing = lrint (brect.origin.x);
858     font_info->max_bounds.rbearing =
859       lrint (brect.size.width - font_info->width);
861 #ifdef NS_IMPL_COCOA
862     /* set up synthItal and the CG font */
863     font_info->synthItal = synthItal;
864     {
865       ATSFontRef atsFont = ATSFontFindFromPostScriptName
866         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
868       if (atsFont == kATSFontRefUnspecified)
869         {
870           /* see if we can get it by dropping italic (then synthesizing) */
871           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
872               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
873                 fontName], kATSOptionFlagsDefault);
874           if (atsFont != kATSFontRefUnspecified)
875               font_info->synthItal = YES;
876           else
877             {
878               /* last resort fallback */
879               atsFont = ATSFontFindFromPostScriptName
880                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
881             }
882         }
883       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
884     }
885 #endif
887     /* set up metrics portion of font struct */
888     font->ascent = lrint([sfont ascender]);
889     font->descent = -lrint(floor(adjusted_descender));
890     font->min_width = ns_char_width(sfont, '|');
891     font->space_width = lrint (ns_char_width (sfont, ' '));
892     font->average_width = lrint (font_info->width);
893     font->max_width = lrint (font_info->max_bounds.width);
894     font->height = lrint (font_info->height);
895     font->underline_position = lrint (font_info->underpos);
896     font->underline_thickness = lrint (font_info->underwidth);
898     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
899     font->props[FONT_FULLNAME_INDEX] =
900       make_unibyte_string (font_info->name, strlen (font_info->name));
901   }
902   UNBLOCK_INPUT;
904   return font_object;
908 /* Close FONT on frame F. */
909 static void
910 nsfont_close (FRAME_PTR f, struct font *font)
912   struct nsfont_info *font_info = (struct nsfont_info *)font;
913   int i;
915   /* FIXME: this occurs apparently due to same failure to detect same font
916             that causes need for cache in nsfont_open () */
917   if (!font_info)
918       return;
920   for (i =0; i<0x100; i++)
921     {
922       xfree (font_info->glyphs[i]);
923       xfree (font_info->metrics[i]);
924     }
925   [font_info->nsfont release];
926 #ifdef NS_IMPL_COCOA
927   CGFontRelease (font_info->cgfont);
928 #endif
929   xfree (font_info->name);
930   xfree (font_info);
934 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
935    return 1.  If not, return 0.  If a font must be opened to check
936    it, return -1. */
937 static int
938 nsfont_has_char (Lisp_Object entity, int c)
940   return -1;
944 /* Return a glyph code of FONT for character C (Unicode code point).
945    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
946 static unsigned int
947 nsfont_encode_char (struct font *font, int c)
949   struct nsfont_info *font_info = (struct nsfont_info *)font;
950   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
951   unsigned short g;
953   if (c > 0xFFFF)
954     return FONT_INVALID_CODE;
956   /* did we already cache this block? */
957   if (!font_info->glyphs[high])
958     ns_uni_to_glyphs (font_info, high);
960   g = font_info->glyphs[high][low];
961   return g == 0xFFFF ? FONT_INVALID_CODE : g;
965 /* Perform the size computation of glyphs of FONT and fill in members
966    of METRICS.  The glyphs are specified by their glyph codes in
967    CODE (length NGLYPHS). */
968 static int
969 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
970                      struct font_metrics *metrics)
972   struct nsfont_info *font_info = (struct nsfont_info *)font;
973   struct font_metrics *pcm;
974   unsigned char high, low;
975   int totalWidth = 0;
976   int i;
978   memset (metrics, 0, sizeof (struct font_metrics));
980   for (i =0; i<nglyphs; i++)
981     {
982       /* get metrics for this glyph, filling cache if need be */
983       /* TODO: get metrics for whole string from an NSLayoutManager
984                (if not too slow) */
985       high = (code[i] & 0xFF00) >> 8;
986       low = code[i] & 0x00FF;
987       if (!font_info->metrics[high])
988         ns_glyph_metrics (font_info, high);
989       pcm = &(font_info->metrics[high][low]);
991       if (metrics->lbearing > totalWidth + pcm->lbearing)
992         metrics->lbearing = totalWidth + pcm->lbearing;
993       if (metrics->rbearing < totalWidth + pcm->rbearing)
994         metrics->rbearing = totalWidth + pcm->rbearing;
995       if (metrics->ascent < pcm->ascent)
996         metrics->ascent = pcm->ascent;
997       if (metrics->descent < pcm->descent)
998         metrics->descent = pcm->descent;
1000       totalWidth += pcm->width;
1001     }
1003   metrics->width = totalWidth;
1005   return totalWidth; /* not specified in doc, but xfont.c does it */
1009 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1010    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
1011    is nonzero, fill the background in advance.  It is assured that
1012    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1013 static int
1014 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1015              int with_background)
1016 /* NOTE: focus and clip must be set
1017      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1019   static char cbuf[1024];
1020   char *c = cbuf;
1021 #ifdef NS_IMPL_GNUSTEP
1022   static float advances[1024];
1023   float *adv = advances;
1024 #else
1025   static CGSize advances[1024];
1026   CGSize *adv = advances;
1027 #endif
1028   struct face *face;
1029   NSRect r;
1030   struct nsfont_info *font = ns_tmp_font;
1031   NSColor *col, *bgCol;
1032   unsigned short *t = s->char2b;
1033   int i, len;
1034   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1035   int end = isComposite ? s->cmp_to : s->nchars;
1037   /* Select face based on input flags */
1038   switch (ns_tmp_flags)
1039     {
1040     case NS_DUMPGLYPH_CURSOR:
1041       face = s->face;
1042       break;
1043     case NS_DUMPGLYPH_MOUSEFACE:
1044       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1045       if (!face)
1046         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1047       break;
1048     default:
1049       face = s->face;
1050     }
1052   r.origin.x = s->x;
1053   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1054     r.origin.x += abs (s->face->box_line_width);
1056   r.origin.y = s->y;
1057   r.size.height = FONT_HEIGHT (font);
1059   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1060      NS to render the string, it will come out differently from the individual
1061      character widths added up because of layout processing. */
1062   {
1063     XCharStruct *cs;
1064     int cwidth, twidth = 0;
1065     int hi, lo;
1066     /* FIXME: composition: no vertical displacement is considered. */
1067     t += s->cmp_from; /* advance into composition */
1068     for (i = s->cmp_from; i < end; i++, t++)
1069       {
1070         hi = (*t & 0xFF00) >> 8;
1071         lo = *t & 0x00FF;
1072         if (isComposite)
1073           {
1074             if (!s->first_glyph->u.cmp.automatic)
1075                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1076             else
1077               {
1078                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1079                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1080                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1081                     cwidth = LGLYPH_WIDTH (glyph);
1082                 else
1083                   {
1084                     cwidth = LGLYPH_WADJUST (glyph);
1085 #ifdef NS_IMPL_GNUSTEP
1086                     *(adv-1) += LGLYPH_XOFF (glyph);
1087 #else
1088                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1089 #endif
1090                   }
1091               }
1092           }
1093         else
1094           {
1095             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1096               ns_glyph_metrics (font, hi);
1097             cwidth = font->metrics[hi][lo].width;
1098           }
1099         twidth += cwidth;
1100 #ifdef NS_IMPL_GNUSTEP
1101         *adv++ = cwidth;
1102         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1103 #else
1104         (*adv++).width = cwidth;
1105 #endif
1106       }
1107     len = adv - advances;
1108     r.size.width = twidth;
1109     *c = 0;
1110   }
1112   /* fill background if requested */
1113   if (with_background && !isComposite)
1114     {
1115       NSRect br = r;
1116       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1117       int mbox_line_width = max (s->face->box_line_width, 0);
1119       if (s->row->full_width_p)
1120         {
1121           if (br.origin.x <= fibw + 1 + mbox_line_width)
1122             {
1123               br.size.width += br.origin.x - mbox_line_width;
1124               br.origin.x = mbox_line_width;
1125             }
1126           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1127                 <= fibw+1)
1128             br.size.width += fibw;
1129         }
1130       if (s->face->box == FACE_NO_BOX)
1131         {
1132           /* expand unboxed top row over internal border */
1133           if (br.origin.y <= fibw + 1 + mbox_line_width)
1134             {
1135               br.size.height += br.origin.y;
1136               br.origin.y = 0;
1137             }
1138         }
1139       else
1140         {
1141           int correction = abs (s->face->box_line_width)+1;
1142           br.origin.y += correction;
1143           br.size.height -= 2*correction;
1144           br.origin.x += correction;
1145           br.size.width -= 2*correction;
1146         }
1148       if (!s->face->stipple)
1149         [(NS_FACE_BACKGROUND (face) != 0
1150           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1151           : FRAME_BACKGROUND_COLOR (s->f)) set];
1152       else
1153         {
1154           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1155           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1156         }
1157       NSRectFill (br);
1158     }
1161   /* set up for character rendering */
1162   r.origin.y = s->ybase;
1164   col = (NS_FACE_FOREGROUND (face) != 0
1165          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1166          : FRAME_FOREGROUND_COLOR (s->f));
1167   /* FIXME: find another way to pass this */
1168   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1169            : (NS_FACE_BACKGROUND (face) != 0
1170               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1171               : FRAME_BACKGROUND_COLOR (s->f)));
1173   /* render under GNUstep using DPS */
1174 #ifdef NS_IMPL_GNUSTEP
1175   {
1176     NSGraphicsContext *context = GSCurrentContext ();
1178     DPSgsave (context);
1179     [font->nsfont set];
1181     /* do erase if "foreground" mode */
1182     if (bgCol != nil)
1183       {
1184         [bgCol set];
1185         DPSmoveto (context, r.origin.x, r.origin.y);
1186 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1187         DPSxshow (context, cbuf, advances, len);
1188         DPSstroke (context);
1189         [col set];
1190 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1191       }
1193     [col set];
1195     /* draw with DPSxshow () */
1196     DPSmoveto (context, r.origin.x, r.origin.y);
1197     DPSxshow (context, cbuf, advances, len);
1198     DPSstroke (context);
1200     DPSgrestore (context);
1201   }
1203 #else  /* NS_IMPL_COCOA */
1204   {
1205     CGContextRef gcontext =
1206       [[NSGraphicsContext currentContext] graphicsPort];
1207     static CGAffineTransform fliptf;
1208     static BOOL firstTime = YES;
1210     if (firstTime)
1211       {
1212         firstTime = NO;
1213         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1214       }
1216     CGContextSaveGState (gcontext);
1218     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1220     CGContextSetFont (gcontext, font->cgfont);
1221     CGContextSetFontSize (gcontext, font->size);
1222     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1223       CGContextSetShouldAntialias (gcontext, 0);
1224     else
1225       CGContextSetShouldAntialias (gcontext, 1);
1227     CGContextSetTextMatrix (gcontext, fliptf);
1229     if (bgCol != nil)
1230       {
1231         /* foreground drawing; erase first to avoid overstrike */
1232         [bgCol set];
1233         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1234         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1235         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1236         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1237       }
1239     [col set];
1241     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1242     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1243                                     advances, len);
1245     if (face->overstrike)
1246       {
1247         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1248         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1249                                         advances, len);
1250       }
1252     CGContextRestoreGState (gcontext);
1253   }
1254 #endif  /* NS_IMPL_COCOA */
1256   /* Draw underline, overline, strike-through. */
1257   ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1259   return to-from;
1264 /* ==========================================================================
1266     Font glyph and metrics caching functions
1268    ========================================================================== */
1270 /* Find and cache corresponding glyph codes for unicode values in given
1271    hi-byte block of 256. */
1272 static void
1273 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1275 #ifdef NS_IMPL_COCOA
1276   static EmacsGlyphStorage *glyphStorage;
1277   static char firstTime = 1;
1278 #endif
1279   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1280   unsigned int i, g, idx;
1281   unsigned short *glyphs;
1283   if (NSFONT_TRACE)
1284     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1285             font_info, block);
1287  BLOCK_INPUT;
1289 #ifdef NS_IMPL_COCOA
1290   if (firstTime)
1291     {
1292       firstTime = 0;
1293       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1294     }
1295 #endif
1297   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1298   if (!unichars || !(font_info->glyphs[block]))
1299     abort ();
1301   /* create a string containing all Unicode characters in this block */
1302   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1303     if (idx < 0xD800 || idx > 0xDFFF)
1304       unichars[i] = idx;
1305     else
1306       unichars[i] = 0xFEFF;
1307   unichars[0x100] = 0;
1309   {
1310 #ifdef NS_IMPL_COCOA
1311     NSString *allChars = [[NSString alloc]
1312                                initWithCharactersNoCopy: unichars
1313                                                  length: 0x100
1314                                            freeWhenDone: NO];
1315     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1316     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1317     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1318     NSUInteger gInd = 0, cInd = 0;
1320     [glyphStorage setString: allChars font: font_info->nsfont];
1321     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1322                         desiredNumberOfCharacters: glyphStorage->maxChar
1323                                        glyphIndex: &gInd characterIndex: &cInd];
1324 #endif
1325     glyphs = font_info->glyphs[block];
1326     for (i = 0; i < 0x100; i++, glyphs++)
1327       {
1328 #ifdef NS_IMPL_GNUSTEP
1329         g = unichars[i];
1330 #else
1331         g = glyphStorage->cglyphs[i];
1332         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1333         if (g > numGlyphs)
1334           g = 0xFFFF; /* hopefully unused... */
1335 #endif
1336         *glyphs = g;
1337       }
1339 #ifdef NS_IMPL_COCOA
1340     [allChars release];
1341 #endif
1342   }
1344   UNBLOCK_INPUT;
1345   xfree (unichars);
1349 /* Determine and cache metrics for corresponding glyph codes in given
1350    hi-byte block of 256. */
1351 static void
1352 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1354   unsigned int i, g;
1355   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1356   NSFont *sfont;
1357   struct font_metrics *metrics;
1359   if (NSFONT_TRACE)
1360     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1361             font_info, block);
1363 #ifdef NS_IMPL_GNUSTEP
1364   /* not implemented yet (as of startup 0.18), so punt */
1365   if (numGlyphs == 0)
1366     numGlyphs = 0x10000;
1367 #endif
1369  BLOCK_INPUT;
1370  sfont = [font_info->nsfont screenFont];
1372   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1373   if (!(font_info->metrics[block]))
1374     abort ();
1376   metrics = font_info->metrics[block];
1377   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1378     {
1379       float w, lb, rb;
1380       NSRect r = [sfont boundingRectForGlyph: g];
1382       w = max ([sfont advancementForGlyph: g].width, 2.0);
1383       metrics->width = lrint (w);
1385       lb = r.origin.x;
1386       rb = r.size.width - w;
1387       if (lb < 0)
1388         metrics->lbearing = round (lb);
1389       if (font_info->ital)
1390         rb += 0.22 * font_info->height;
1391       metrics->rbearing = lrint (w + rb);
1393       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1394  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1395       metrics->ascent = r.size.height - metrics->descent;
1396 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1397     }
1398   UNBLOCK_INPUT;
1402 #ifdef NS_IMPL_COCOA
1403 /* helper for font glyph setup */
1404 @implementation EmacsGlyphStorage
1406 - init
1408   return [self initWithCapacity: 1024];
1411 - initWithCapacity: (unsigned long) c
1413   self = [super init];
1414   maxChar = 0;
1415   maxGlyph = 0;
1416   dict = [NSMutableDictionary new];
1417   cglyphs = xmalloc (c * sizeof (CGGlyph));
1418   return self;
1421 - (void) dealloc
1423   if (attrStr != nil)
1424     [attrStr release];
1425   [dict release];
1426   xfree (cglyphs);
1427   [super dealloc];
1430 - (void) setString: (NSString *)str font: (NSFont *)font
1432   [dict setObject: font forKey: NSFontAttributeName];
1433   if (attrStr != nil)
1434     [attrStr release];
1435   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1436   maxChar = [str length];
1437   maxGlyph = 0;
1440 /* NSGlyphStorage protocol */
1441 - (NSUInteger)layoutOptions
1443   return 0;
1446 - (NSAttributedString *)attributedString
1448   return attrStr;
1451 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1452         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1453         characterIndex: (NSUInteger)charIndex
1455   len = glyphIndex+length;
1456   for (i =glyphIndex; i<len; i++)
1457     cglyphs[i] = glyphs[i-glyphIndex];
1458   if (len > maxGlyph)
1459     maxGlyph = len;
1462 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1463         forGlyphAtIndex: (NSUInteger)glyphIndex
1465   return;
1468 @end
1469 #endif /* NS_IMPL_COCOA */
1472 /* Debugging */
1473 void
1474 ns_dump_glyphstring (struct glyph_string *s)
1476   int i;
1478   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1479 "overlap = %d, bg_filled = %d:",
1480            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1481            s->row->overlapping_p, s->background_filled_p);
1482   for (i =0; i<s->nchars; i++)
1483     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1484   fprintf (stderr, "\n");
1488 void
1489 syms_of_nsfont (void)
1491   nsfont_driver.type = Qns;
1492   register_font_driver (&nsfont_driver, NULL);
1493   DEFSYM (Qapple, "apple");
1494   DEFSYM (Qroman, "roman");
1495   DEFSYM (Qmedium, "medium");
1496   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1497                doc: /* Internal use: maps font registry to Unicode script. */);