Avoid GDB 7.5 warnings about "set main" in src/.gdbinit.
[emacs.git] / src / nsfont.m
blob412a6777c643f14aac9be2d487299dec5b69d3dc
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 (SSDATA (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 = -1.0;
244   NSString *cstr = [NSString stringWithFormat: @"%c", c];
246 #ifdef NS_IMPL_COCOA
247   NSGlyph glyph = [sfont glyphWithName: cstr];
248   if (glyph)
249     w = [sfont advancementForGlyph: glyph].width;
250 #endif
252   if (w < 0.0)
253     {
254       NSDictionary *attrsDictionary =
255         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
256       w = [cstr sizeWithAttributes: attrsDictionary].width;
257     }
259   return max (w, 1.0);
262 /* Return average width over ASCII printable characters for SFONT.  */
264 static NSString *ascii_printable;
266 static int
267 ns_ascii_average_width (NSFont *sfont)
269   float w = -1.0;
271   if (!ascii_printable)
272     {
273       char chars[96];
274       int ch;
275       for (ch = 0; ch < 95; ch++)
276         chars[ch] = ' ' + ch;
277       chars[95] = '\0';
279       ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
280     }
282 #ifdef NS_IMPL_COCOA
283   NSGlyph glyph = [sfont glyphWithName: ascii_printable];
284   if (glyph)
285     w = [sfont advancementForGlyph: glyph].width;
286 #endif
288   if (w < 0.0)
289     {
290       NSDictionary *attrsDictionary =
291         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
292       w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
293     }
295   return lrint (w / 95.0);
299 /* Return whether set1 covers set2 to a reasonable extent given by pct.
300    We check, out of each 16 Unicode char range containing chars in set2,
301    whether at least one character is present in set1.
302    This must be true for pct of the pairs to consider it covering. */
303 static BOOL
304 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
306     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
307     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
308     int i, off = 0, tot = 0;
310     /* Work around what appears to be a GNUstep bug.
311        See <http://bugs.gnu.org/11853>.  */
312     if (! (bytes1 && bytes2))
313       return NO;
315     for (i=0; i<4096; i++, bytes1++, bytes2++)
316         if (*bytes2)
317           {
318             tot++;
319             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
320                 off++;
321           }
322 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
323     return (float)off / tot < 1.0 - pct;
327 /* Convert :lang property to a script.  Use of :lang property by font backend
328    seems to be limited for now (2009/05) to ja, zh, and ko. */
329 static NSString
330 *ns_lang_to_script (Lisp_Object lang)
332     if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
333         return @"han";
334     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
335              have more characters. */
336     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
337         return @"han";
338     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
339         return @"hangul";
340     else
341         return @"";
345 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
346    everyone just use some standard Unicode names for these?) */
347 static NSString
348 *ns_otf_to_script (Lisp_Object otf)
350     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
351     return CONSP (script)
352         ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
353         : @"";
357 /* Convert a font registry, such as  */
358 static NSString
359 *ns_registry_to_script (char *reg)
361     Lisp_Object script, r, rts = Vns_reg_to_script;
362     while CONSP (rts)
363       {
364         r = XCAR (XCAR (rts));
365         if (!strncmp(SSDATA(r), reg, strlen(SSDATA(r))))
366           {
367             script = XCDR (XCAR (rts));
368             return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
369           }
370         rts = XCDR (rts);
371       }
372     return  @"";
376 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
377    plus registry regular property, for something that can be mapped to a
378    Unicode script.  Empty string returned if no script spec found. */
379 static NSString
380 *ns_get_req_script (Lisp_Object font_spec)
382     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
383     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
385     /* The extra-bundle properties have priority. */
386     for ( ; CONSP (extra); extra = XCDR (extra))
387       {
388         Lisp_Object tmp = XCAR (extra);
389         if (CONSP (tmp))
390           {
391             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
392             if (EQ (key, QCscript) && SYMBOLP (val))
393                 return [NSString stringWithUTF8String:
394                             SSDATA (SYMBOL_NAME (val))];
395             if (EQ (key, QClang) && SYMBOLP (val))
396                 return ns_lang_to_script (val);
397             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
398                 return ns_otf_to_script (val);
399           }
400       }
402     /* If we get here, check the charset portion of the registry. */
403     if (! NILP (reg))
404       {
405         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
406            (which causes box rendering if we don't treat it like iso8858-1)
407            but also for ascii (which causes unnecessary font substitution). */
408 #if 0
409         if (EQ (reg, Qiso10646_1))
410           reg = Qiso8859_1;
411 #endif
412         return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
413       }
415     return @"";
419 /* This small function is static in fontset.c.  If it can be made public for
420    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
421 static void
422 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
424     if (EQ (XCAR (arg), val))
425       {
426         if (CONSP (range))
427           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
428         else
429           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
430       }
434 /* Use the Unicode range information in Vchar_script_table to convert a script
435    name into an NSCharacterSet. */
436 static NSCharacterSet
437 *ns_script_to_charset (NSString *scriptName)
439     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
440     Lisp_Object script = intern ([scriptName UTF8String]);
441     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
443     if (! NILP (Fmemq (script, script_list)))
444       {
445         Lisp_Object ranges, range_list;
447         ranges = Fcons (script, Qnil);
448         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
449                         ranges);
450         range_list = Fnreverse (XCDR (ranges));
451         if (! NILP (range_list))
452           {
453             for (; CONSP (range_list); range_list = XCDR (range_list))
454               {
455                 int start = XINT (XCAR (XCAR (range_list)));
456                 int end = XINT (XCDR (XCAR (range_list)));
457                 if (NSFONT_TRACE)
458                     debug_print (XCAR (range_list));
459                 if (end < 0x10000)
460                     [charset addCharactersInRange:
461                         NSMakeRange (start, end-start)];
462               }
463           }
464       }
465     return charset;
469 /* Return an array of font families containing characters for the given
470    script, for the given coverage criterion, including at least LastResort.
471    Results are cached by script for faster access.
472    If none are found, we reduce the percentage and try again, until 5%.
473    This provides a font with at least some characters if such can be found.
474    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
475    (b) need approximate match as fonts covering full Unicode ranges are rare. */
476 static NSSet
477 *ns_get_covering_families (NSString *script, float pct)
479     static NSMutableDictionary *scriptToFamilies = nil;
480     NSMutableSet *families;
482     if (NSFONT_TRACE)
483         NSLog(@"Request covering families for script: '%@'", script);
485     if (scriptToFamilies == nil)
486         scriptToFamilies = [[NSMutableDictionary alloc] init];
488     if ((families = [scriptToFamilies objectForKey: script]) == nil)
489       {
490         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
491         NSArray *allFamilies = [fontMgr availableFontFamilies];
493         if ([script length] == 0)
494             families = [NSMutableSet setWithArray: allFamilies];
495         else
496           {
497             NSCharacterSet *charset = ns_script_to_charset (script);
498             NSString *family;
499             families = [NSMutableSet setWithCapacity: 10];
500             while (1)
501               {
502                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
503                 while ((family = [allFamiliesEnum nextObject]))
504                   {
505                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
506                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
507                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
508                     if (fset == nil)
509                       fset = [NSCharacterSet characterSetWithRange:
510                                                NSMakeRange (0, 127)];
511                     if (ns_charset_covers(fset, charset, pct))
512                         [families addObject: family];
513                   }
514                 pct -= 0.2;
515                 if ([families count] > 0 || pct < 0.05)
516                     break;
517               }
518             [charset release];
519           }
520 #ifdef NS_IMPL_COCOA
521         if ([families count] == 0)
522             [families addObject: @"LastResort"];
523 #endif
524         [scriptToFamilies setObject: families forKey: script];
525       }
527     if (NSFONT_TRACE)
528         NSLog(@"    returning %d families", [families count]);
529     return families;
533 /* Implementation for list() and match().  List() can return nil, match()
534 must return something.  Strategy is to drop family name from attribute
535 matching set for match. */
536 static Lisp_Object
537 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
539     Lisp_Object tem, list = Qnil;
540     NSFontDescriptor *fdesc, *desc;
541     NSMutableSet *fkeys;
542     NSArray *matchingDescs;
543     NSEnumerator *dEnum;
544     NSString *family;
545     NSSet *cFamilies;
546     BOOL foundItal = NO;
548     if (NSFONT_TRACE)
549       {
550         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
551                  (isMatch ? "match" : "list"));
552         debug_print (font_spec);
553       }
555     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
557     fdesc = ns_spec_to_descriptor (font_spec);
558     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
559     if (isMatch)
560         [fkeys removeObject: NSFontFamilyAttribute];
562     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
563     if (NSFONT_TRACE)
564         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
565               [matchingDescs count]);
567     for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
568       {
569         if (![cFamilies containsObject:
570                  [desc objectForKey: NSFontFamilyAttribute]])
571             continue;
572         tem = ns_descriptor_to_entity (desc,
573                                          AREF (font_spec, FONT_EXTRA_INDEX),
574                                        NULL);
575         if (isMatch)
576           return tem;
577         list = Fcons (tem, list);
578         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
579             foundItal = YES;
580       }
582     /* Add synthItal member if needed. */
583     family = [fdesc objectForKey: NSFontFamilyAttribute];
584     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
585       {
586         NSFontDescriptor *s1 = [NSFontDescriptor new];
587         NSFontDescriptor *sDesc
588           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
589               fontDescriptorWithFamily: family];
590         list = Fcons (ns_descriptor_to_entity (sDesc,
591                                          AREF (font_spec, FONT_EXTRA_INDEX),
592                                          "synthItal"), list);
593         [s1 release];
594       }
596     /* Return something if was a match and nothing found. */
597     if (isMatch)
598       return ns_fallback_entity ();
600     if (NSFONT_TRACE)
601         fprintf (stderr, "    Returning %"pI"d entities.\n",
602                  XINT (Flength (list)));
604     return list;
609 /* ==========================================================================
611     Font driver implementation
613    ========================================================================== */
616 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
617 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
618 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
619 static Lisp_Object nsfont_list_family (Lisp_Object frame);
620 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
621                                  int pixel_size);
622 static void nsfont_close (FRAME_PTR f, struct font *font);
623 static int nsfont_has_char (Lisp_Object entity, int c);
624 static unsigned int nsfont_encode_char (struct font *font, int c);
625 static int nsfont_text_extents (struct font *font, unsigned int *code,
626                                 int nglyphs, struct font_metrics *metrics);
627 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
628                         int with_background);
630 struct font_driver nsfont_driver =
631   {
632     0,                          /* Qns */
633     1,                          /* case sensitive */
634     nsfont_get_cache,
635     nsfont_list,
636     nsfont_match,
637     nsfont_list_family,
638     NULL,                       /*free_entity */
639     nsfont_open,
640     nsfont_close,
641     NULL,                       /* prepare_face */
642     NULL,                       /* done_face */
643     nsfont_has_char,
644     nsfont_encode_char,
645     nsfont_text_extents,
646     nsfont_draw,
647     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
648                  anchor_point, otf_capability, otf_driver,
649                  start_for_frame, end_for_frame, shape */
650   };
653 /* Return a cache of font-entities on FRAME.  The cache must be a
654    cons whose cdr part is the actual cache area.  */
655 static Lisp_Object
656 nsfont_get_cache (FRAME_PTR frame)
658   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
659   return (dpyinfo->name_list_element);
663 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
664    **list** of font-entities.  This and match () are sole APIs that allocate
665    font-entities.  Properties to be considered (2009/05/19) are:
666    regular: foundry, family, adstyle, registry
667    extended: script, lang, otf
668   "Extended" properties are not part of the vector but get stored as
669    lisp properties under FONT_EXTRA_INDEX.
671    The returned entities should have type set (to 'ns), plus the following:
672    foundry, family, adstyle, registry,
673    weight, slant, width, size (0 if scalable),
674    dpi, spacing, avgwidth (0 if scalable)  */
675 static Lisp_Object
676 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
678     return ns_findfonts (font_spec, NO);
682 /* Return a font entity most closely matching with FONT_SPEC on
683    FRAME.  The closeness is determined by the font backend, thus
684    `face-font-selection-order' is ignored here.
685    Properties to be considered are same as for list(). */
686 static Lisp_Object
687 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
689     return ns_findfonts(font_spec, YES);
693 /* List available families.  The value is a list of family names
694    (symbols). */
695 static Lisp_Object
696 nsfont_list_family (Lisp_Object frame)
698   Lisp_Object list = Qnil;
699   NSEnumerator *families =
700     [[[NSFontManager sharedFontManager] availableFontFamilies]
701       objectEnumerator];
702   NSString *family;
703   while ((family = [families nextObject]))
704       list = Fcons (intern ([family UTF8String]), list);
705   /* FIXME: escape the name? */
707   if (NSFONT_TRACE)
708     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
709              XINT (Flength (list)));
711   return list;
715 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
716    scalable, open it with PIXEL_SIZE.  */
717 static Lisp_Object
718 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
720   BOOL synthItal;
721   unsigned int traits = 0;
722   struct nsfont_info *font_info;
723   struct font *font;
724   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
725   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
726   NSString *family;
727   NSFont *nsfont, *sfont;
728   Lisp_Object tem;
729   NSRect brect;
730   Lisp_Object font_object;
731   int fixLeopardBug;
732   static NSMutableDictionary *fontCache = nil;
733   NSNumber *cached;
735   /* 2008/03/08: The same font may end up being requested for different
736      entities, due to small differences in numeric values or other issues,
737      or for different copies of the same entity.  Therefore we cache to
738      avoid creating multiple struct font objects (with metrics cache, etc.)
739      for the same NSFont object. */
740   if (fontCache == nil)
741     fontCache = [[NSMutableDictionary alloc] init];
743   if (NSFONT_TRACE)
744     {
745       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
746       debug_print (font_entity);
747     }
749   if (pixel_size <= 0)
750     {
751       /* try to get it out of frame params */
752         Lisp_Object tem = get_frame_param (f, Qfontsize);
753         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
754     }
756   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
757   synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
758                                        9);
759   family = ns_get_family (font_entity);
760   if (family == nil)
761     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
762   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
763      when setting family in ns_spec_to_descriptor(). */
764   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
765       traits |= NSBoldFontMask;
766   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
767       traits |= NSItalicFontMask;
769   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
770   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
771   nsfont = [fontMgr fontWithFamily: family
772                             traits: traits weight: fixLeopardBug
773                               size: pixel_size];
774   /* if didn't find, try synthetic italic */
775   if (nsfont == nil && synthItal)
776     {
777       nsfont = [fontMgr fontWithFamily: family
778                                 traits: traits & ~NSItalicFontMask
779                                 weight: fixLeopardBug size: pixel_size];
780     }
781 #ifdef NS_IMPL_COCOA
782   /* LastResort not really a family */
783   if (nsfont == nil && [@"LastResort" isEqualToString: family])
784       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
785 #endif
787   if (nsfont == nil)
788     {
789       message_with_string ("*** Warning: font in family '%s' not found",
790                           build_string ([family UTF8String]), 1);
791       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
792     }
794   if (NSFONT_TRACE)
795     NSLog (@"%@\n", nsfont);
797   /* Check the cache */
798   cached = [fontCache objectForKey: nsfont];
799   if (cached != nil && !synthItal)
800     {
801       if (NSFONT_TRACE)
802         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
803       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
804       XHASH (font_object) = [cached unsignedLongValue];
805       return font_object;
806     }
807   else
808     {
809       font_object = font_make_object (VECSIZE (struct nsfont_info),
810                                       font_entity, pixel_size);
811       if (!synthItal)
812         [fontCache setObject: [NSNumber numberWithUnsignedLong:
813                                           (unsigned long) XHASH (font_object)]
814                       forKey: nsfont];
815     }
817   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
818   font = (struct font *) font_info;
819   if (!font)
820     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
822   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
823   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
825   BLOCK_INPUT;
827   /* for metrics */
828   sfont = [nsfont screenFont];
829   if (sfont == nil)
830     sfont = nsfont;
832   /* non-metric backend font struct fields */
833   font = (struct font *) font_info;
834   font->pixel_size = [sfont pointSize];
835   font->driver = &nsfont_driver;
836   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
837   font->encoding_charset = -1;
838   font->repertory_charset = -1;
839   font->default_ascent = 0;
840   font->vertical_centering = 0;
841   font->baseline_offset = 0;
842   font->relative_compose = 0;
843   font->font_encoder = NULL;
845   font->props[FONT_FORMAT_INDEX] = Qns;
846   font->props[FONT_FILE_INDEX] = Qnil;
848   {
849     const char *fontName = [[nsfont fontName] UTF8String];
851     /* The values specified by fonts are not always exact. For
852      * example, a 6x8 font could specify that the descender is
853      * -2.00000405... (represented by 0xc000000220000000).  Without
854      * adjustment, the code below would round the descender to -3,
855      * resulting in a font that would be one pixel higher than
856      * intended. */
857     CGFloat adjusted_descender = [sfont descender] + 0.0001;
859 #ifdef NS_IMPL_GNUSTEP
860     font_info->nsfont = sfont;
861 #else
862     font_info->nsfont = nsfont;
863 #endif
864     [font_info->nsfont retain];
866     /* set up ns_font (defined in nsgui.h) */
867     font_info->name = xstrdup (fontName);
868     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
869     font_info->ital =
870       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
872     /* Metrics etc.; some fonts return an unusually large max advance, so we
873        only use it for fonts that have wide characters. */
874     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
875       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
877     brect =  [sfont boundingRectForFont];
879     font_info->underpos = [sfont underlinePosition];
880     font_info->underwidth = [sfont underlineThickness];
881     font_info->size = font->pixel_size;
883     /* max bounds */
884     font_info->max_bounds.ascent = lrint ([sfont ascender]);
885     /* Descender is usually negative.  Use floor to avoid
886        clipping descenders. */
887     font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
888     font_info->height =
889       font_info->max_bounds.ascent + font_info->max_bounds.descent;
890     font_info->max_bounds.width = lrint (font_info->width);
891     font_info->max_bounds.lbearing = lrint (brect.origin.x);
892     font_info->max_bounds.rbearing =
893       lrint (brect.size.width - font_info->width);
895 #ifdef NS_IMPL_COCOA
896     /* set up synthItal and the CG font */
897     font_info->synthItal = synthItal;
898     {
899       ATSFontRef atsFont = ATSFontFindFromPostScriptName
900         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
902       if (atsFont == kATSFontRefUnspecified)
903         {
904           /* see if we can get it by dropping italic (then synthesizing) */
905           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
906               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
907                 fontName], kATSOptionFlagsDefault);
908           if (atsFont != kATSFontRefUnspecified)
909               font_info->synthItal = YES;
910           else
911             {
912               /* last resort fallback */
913               atsFont = ATSFontFindFromPostScriptName
914                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
915             }
916         }
917       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
918     }
919 #endif
921     /* set up metrics portion of font struct */
922     font->ascent = lrint([sfont ascender]);
923     font->descent = -lrint(floor(adjusted_descender));
924     font->space_width = lrint (ns_char_width (sfont, ' '));
925     font->max_width = lrint (font_info->max_bounds.width);
926     font->min_width = font->space_width;  /* Approximate.  */
927     font->average_width = ns_ascii_average_width (sfont);
929     font->height = lrint (font_info->height);
930     font->underline_position = lrint (font_info->underpos);
931     font->underline_thickness = lrint (font_info->underwidth);
933     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
934     font->props[FONT_FULLNAME_INDEX] =
935       make_unibyte_string (font_info->name, strlen (font_info->name));
936   }
937   UNBLOCK_INPUT;
939   return font_object;
943 /* Close FONT on frame F. */
944 static void
945 nsfont_close (FRAME_PTR f, struct font *font)
947   struct nsfont_info *font_info = (struct nsfont_info *)font;
948   int i;
950   /* FIXME: this occurs apparently due to same failure to detect same font
951             that causes need for cache in nsfont_open () */
952   if (!font_info)
953       return;
955   for (i =0; i<0x100; i++)
956     {
957       xfree (font_info->glyphs[i]);
958       xfree (font_info->metrics[i]);
959     }
960   [font_info->nsfont release];
961 #ifdef NS_IMPL_COCOA
962   CGFontRelease (font_info->cgfont);
963 #endif
964   xfree (font_info->name);
965   xfree (font_info);
969 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
970    return 1.  If not, return 0.  If a font must be opened to check
971    it, return -1. */
972 static int
973 nsfont_has_char (Lisp_Object entity, int c)
975   return -1;
979 /* Return a glyph code of FONT for character C (Unicode code point).
980    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
981 static unsigned int
982 nsfont_encode_char (struct font *font, int c)
984   struct nsfont_info *font_info = (struct nsfont_info *)font;
985   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
986   unsigned short g;
988   if (c > 0xFFFF)
989     return FONT_INVALID_CODE;
991   /* did we already cache this block? */
992   if (!font_info->glyphs[high])
993     ns_uni_to_glyphs (font_info, high);
995   g = font_info->glyphs[high][low];
996   return g == 0xFFFF ? FONT_INVALID_CODE : g;
1000 /* Perform the size computation of glyphs of FONT and fill in members
1001    of METRICS.  The glyphs are specified by their glyph codes in
1002    CODE (length NGLYPHS). */
1003 static int
1004 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
1005                      struct font_metrics *metrics)
1007   struct nsfont_info *font_info = (struct nsfont_info *)font;
1008   struct font_metrics *pcm;
1009   unsigned char high, low;
1010   int totalWidth = 0;
1011   int i;
1013   memset (metrics, 0, sizeof (struct font_metrics));
1015   for (i =0; i<nglyphs; i++)
1016     {
1017       /* get metrics for this glyph, filling cache if need be */
1018       /* TODO: get metrics for whole string from an NSLayoutManager
1019                (if not too slow) */
1020       high = (code[i] & 0xFF00) >> 8;
1021       low = code[i] & 0x00FF;
1022       if (!font_info->metrics[high])
1023         ns_glyph_metrics (font_info, high);
1024       pcm = &(font_info->metrics[high][low]);
1026       if (metrics->lbearing > totalWidth + pcm->lbearing)
1027         metrics->lbearing = totalWidth + pcm->lbearing;
1028       if (metrics->rbearing < totalWidth + pcm->rbearing)
1029         metrics->rbearing = totalWidth + pcm->rbearing;
1030       if (metrics->ascent < pcm->ascent)
1031         metrics->ascent = pcm->ascent;
1032       if (metrics->descent < pcm->descent)
1033         metrics->descent = pcm->descent;
1035       totalWidth += pcm->width;
1036     }
1038   metrics->width = totalWidth;
1040   return totalWidth; /* not specified in doc, but xfont.c does it */
1044 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1045    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
1046    is nonzero, fill the background in advance.  It is assured that
1047    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1048 static int
1049 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1050              int with_background)
1051 /* NOTE: focus and clip must be set
1052      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1054   static char cbuf[1024];
1055   char *c = cbuf;
1056 #ifdef NS_IMPL_GNUSTEP
1057   static float advances[1024];
1058   float *adv = advances;
1059 #else
1060   static CGSize advances[1024];
1061   CGSize *adv = advances;
1062 #endif
1063   struct face *face;
1064   NSRect r;
1065   struct nsfont_info *font = ns_tmp_font;
1066   NSColor *col, *bgCol;
1067   unsigned short *t = s->char2b;
1068   int i, len;
1069   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1070   int end = isComposite ? s->cmp_to : s->nchars;
1072   /* Select face based on input flags */
1073   switch (ns_tmp_flags)
1074     {
1075     case NS_DUMPGLYPH_CURSOR:
1076       face = s->face;
1077       break;
1078     case NS_DUMPGLYPH_MOUSEFACE:
1079       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1080       if (!face)
1081         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1082       break;
1083     default:
1084       face = s->face;
1085     }
1087   r.origin.x = s->x;
1088   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1089     r.origin.x += abs (s->face->box_line_width);
1091   r.origin.y = s->y;
1092   r.size.height = FONT_HEIGHT (font);
1094   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1095      NS to render the string, it will come out differently from the individual
1096      character widths added up because of layout processing. */
1097   {
1098     int cwidth, twidth = 0;
1099     int hi, lo;
1100     /* FIXME: composition: no vertical displacement is considered. */
1101     t += s->cmp_from; /* advance into composition */
1102     for (i = s->cmp_from; i < end; i++, t++)
1103       {
1104         hi = (*t & 0xFF00) >> 8;
1105         lo = *t & 0x00FF;
1106         if (isComposite)
1107           {
1108             if (!s->first_glyph->u.cmp.automatic)
1109                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1110             else
1111               {
1112                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1113                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1114                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1115                     cwidth = LGLYPH_WIDTH (glyph);
1116                 else
1117                   {
1118                     cwidth = LGLYPH_WADJUST (glyph);
1119 #ifdef NS_IMPL_GNUSTEP
1120                     *(adv-1) += LGLYPH_XOFF (glyph);
1121 #else
1122                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1123 #endif
1124                   }
1125               }
1126           }
1127         else
1128           {
1129             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1130               ns_glyph_metrics (font, hi);
1131             cwidth = font->metrics[hi][lo].width;
1132           }
1133         twidth += cwidth;
1134 #ifdef NS_IMPL_GNUSTEP
1135         *adv++ = cwidth;
1136         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1137 #else
1138         (*adv++).width = cwidth;
1139 #endif
1140       }
1141     len = adv - advances;
1142     r.size.width = twidth;
1143     *c = 0;
1144   }
1146   /* fill background if requested */
1147   if (with_background && !isComposite)
1148     {
1149       NSRect br = r;
1150       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1151       int mbox_line_width = max (s->face->box_line_width, 0);
1153       if (s->row->full_width_p)
1154         {
1155           if (br.origin.x <= fibw + 1 + mbox_line_width)
1156             {
1157               br.size.width += br.origin.x - mbox_line_width;
1158               br.origin.x = mbox_line_width;
1159             }
1160           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1161                 <= fibw+1)
1162             br.size.width += fibw;
1163         }
1164       if (s->face->box == FACE_NO_BOX)
1165         {
1166           /* expand unboxed top row over internal border */
1167           if (br.origin.y <= fibw + 1 + mbox_line_width)
1168             {
1169               br.size.height += br.origin.y;
1170               br.origin.y = 0;
1171             }
1172         }
1173       else
1174         {
1175           int correction = abs (s->face->box_line_width)+1;
1176           br.origin.y += correction;
1177           br.size.height -= 2*correction;
1178           br.origin.x += correction;
1179           br.size.width -= 2*correction;
1180         }
1182       if (!s->face->stipple)
1183         [(NS_FACE_BACKGROUND (face) != 0
1184           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1185           : FRAME_BACKGROUND_COLOR (s->f)) set];
1186       else
1187         {
1188           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1189           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1190         }
1191       NSRectFill (br);
1192     }
1195   /* set up for character rendering */
1196   r.origin.y = s->ybase;
1198   col = (NS_FACE_FOREGROUND (face) != 0
1199          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1200          : FRAME_FOREGROUND_COLOR (s->f));
1201   /* FIXME: find another way to pass this */
1202   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1203            : (NS_FACE_BACKGROUND (face) != 0
1204               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1205               : FRAME_BACKGROUND_COLOR (s->f)));
1207   /* render under GNUstep using DPS */
1208 #ifdef NS_IMPL_GNUSTEP
1209   {
1210     NSGraphicsContext *context = GSCurrentContext ();
1212     DPSgsave (context);
1213     [font->nsfont set];
1215     /* do erase if "foreground" mode */
1216     if (bgCol != nil)
1217       {
1218         [bgCol set];
1219         DPSmoveto (context, r.origin.x, r.origin.y);
1220 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1221         DPSxshow (context, cbuf, advances, len);
1222         DPSstroke (context);
1223         [col set];
1224 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1225       }
1227     [col set];
1229     /* draw with DPSxshow () */
1230     DPSmoveto (context, r.origin.x, r.origin.y);
1231     DPSxshow (context, cbuf, advances, len);
1232     DPSstroke (context);
1234     DPSgrestore (context);
1235   }
1237 #else  /* NS_IMPL_COCOA */
1238   {
1239     CGContextRef gcontext =
1240       [[NSGraphicsContext currentContext] graphicsPort];
1241     static CGAffineTransform fliptf;
1242     static BOOL firstTime = YES;
1244     if (firstTime)
1245       {
1246         firstTime = NO;
1247         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1248       }
1250     CGContextSaveGState (gcontext);
1252     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1254     CGContextSetFont (gcontext, font->cgfont);
1255     CGContextSetFontSize (gcontext, font->size);
1256     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1257       CGContextSetShouldAntialias (gcontext, 0);
1258     else
1259       CGContextSetShouldAntialias (gcontext, 1);
1261     CGContextSetTextMatrix (gcontext, fliptf);
1263     if (bgCol != nil)
1264       {
1265         /* foreground drawing; erase first to avoid overstrike */
1266         [bgCol set];
1267         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1268         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1269         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1270         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1271       }
1273     [col set];
1275     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1276     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1277                                     advances, len);
1279     if (face->overstrike)
1280       {
1281         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1282         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1283                                         advances, len);
1284       }
1286     CGContextRestoreGState (gcontext);
1287   }
1288 #endif  /* NS_IMPL_COCOA */
1290   /* Draw underline, overline, strike-through. */
1291   ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1293   return to-from;
1298 /* ==========================================================================
1300     Font glyph and metrics caching functions
1302    ========================================================================== */
1304 /* Find and cache corresponding glyph codes for unicode values in given
1305    hi-byte block of 256. */
1306 static void
1307 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1309 #ifdef NS_IMPL_COCOA
1310   static EmacsGlyphStorage *glyphStorage;
1311   static char firstTime = 1;
1312 #endif
1313   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1314   unsigned int i, g, idx;
1315   unsigned short *glyphs;
1317   if (NSFONT_TRACE)
1318     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1319             font_info, block);
1321  BLOCK_INPUT;
1323 #ifdef NS_IMPL_COCOA
1324   if (firstTime)
1325     {
1326       firstTime = 0;
1327       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1328     }
1329 #endif
1331   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1332   if (!unichars || !(font_info->glyphs[block]))
1333     abort ();
1335   /* create a string containing all Unicode characters in this block */
1336   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1337     if (idx < 0xD800 || idx > 0xDFFF)
1338       unichars[i] = idx;
1339     else
1340       unichars[i] = 0xFEFF;
1341   unichars[0x100] = 0;
1343   {
1344 #ifdef NS_IMPL_COCOA
1345     NSString *allChars = [[NSString alloc]
1346                                initWithCharactersNoCopy: unichars
1347                                                  length: 0x100
1348                                            freeWhenDone: NO];
1349     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1350     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1351     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1352     NSUInteger gInd = 0, cInd = 0;
1354     [glyphStorage setString: allChars font: font_info->nsfont];
1355     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1356                         desiredNumberOfCharacters: glyphStorage->maxChar
1357                                        glyphIndex: &gInd characterIndex: &cInd];
1358 #endif
1359     glyphs = font_info->glyphs[block];
1360     for (i = 0; i < 0x100; i++, glyphs++)
1361       {
1362 #ifdef NS_IMPL_GNUSTEP
1363         g = unichars[i];
1364 #else
1365         g = glyphStorage->cglyphs[i];
1366         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1367         if (g > numGlyphs)
1368           g = 0xFFFF; /* hopefully unused... */
1369 #endif
1370         *glyphs = g;
1371       }
1373 #ifdef NS_IMPL_COCOA
1374     [allChars release];
1375 #endif
1376   }
1378   UNBLOCK_INPUT;
1379   xfree (unichars);
1383 /* Determine and cache metrics for corresponding glyph codes in given
1384    hi-byte block of 256. */
1385 static void
1386 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1388   unsigned int i, g;
1389   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1390   NSFont *sfont;
1391   struct font_metrics *metrics;
1393   if (NSFONT_TRACE)
1394     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1395             font_info, block);
1397 #ifdef NS_IMPL_GNUSTEP
1398   /* not implemented yet (as of startup 0.18), so punt */
1399   if (numGlyphs == 0)
1400     numGlyphs = 0x10000;
1401 #endif
1403  BLOCK_INPUT;
1404  sfont = [font_info->nsfont screenFont];
1406   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1407   if (!(font_info->metrics[block]))
1408     abort ();
1410   metrics = font_info->metrics[block];
1411   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1412     {
1413       float w, lb, rb;
1414       NSRect r = [sfont boundingRectForGlyph: g];
1416       w = max ([sfont advancementForGlyph: g].width, 2.0);
1417       metrics->width = lrint (w);
1419       lb = r.origin.x;
1420       rb = r.size.width - w;
1421       if (lb < 0)
1422         metrics->lbearing = round (lb);
1423       if (font_info->ital)
1424         rb += 0.22 * font_info->height;
1425       metrics->rbearing = lrint (w + rb);
1427       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1428  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1429       metrics->ascent = r.size.height - metrics->descent;
1430 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1431     }
1432   UNBLOCK_INPUT;
1436 #ifdef NS_IMPL_COCOA
1437 /* helper for font glyph setup */
1438 @implementation EmacsGlyphStorage
1440 - init
1442   return [self initWithCapacity: 1024];
1445 - initWithCapacity: (unsigned long) c
1447   self = [super init];
1448   maxChar = 0;
1449   maxGlyph = 0;
1450   dict = [NSMutableDictionary new];
1451   cglyphs = xmalloc (c * sizeof (CGGlyph));
1452   return self;
1455 - (void) dealloc
1457   if (attrStr != nil)
1458     [attrStr release];
1459   [dict release];
1460   xfree (cglyphs);
1461   [super dealloc];
1464 - (void) setString: (NSString *)str font: (NSFont *)font
1466   [dict setObject: font forKey: NSFontAttributeName];
1467   if (attrStr != nil)
1468     [attrStr release];
1469   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1470   maxChar = [str length];
1471   maxGlyph = 0;
1474 /* NSGlyphStorage protocol */
1475 - (NSUInteger)layoutOptions
1477   return 0;
1480 - (NSAttributedString *)attributedString
1482   return attrStr;
1485 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1486         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1487         characterIndex: (NSUInteger)charIndex
1489   len = glyphIndex+length;
1490   for (i =glyphIndex; i<len; i++)
1491     cglyphs[i] = glyphs[i-glyphIndex];
1492   if (len > maxGlyph)
1493     maxGlyph = len;
1496 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1497         forGlyphAtIndex: (NSUInteger)glyphIndex
1499   return;
1502 @end
1503 #endif /* NS_IMPL_COCOA */
1506 /* Debugging */
1507 void
1508 ns_dump_glyphstring (struct glyph_string *s)
1510   int i;
1512   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1513 "overlap = %d, bg_filled = %d:",
1514            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1515            s->row->overlapping_p, s->background_filled_p);
1516   for (i =0; i<s->nchars; i++)
1517     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1518   fprintf (stderr, "\n");
1522 void
1523 syms_of_nsfont (void)
1525   nsfont_driver.type = Qns;
1526   register_font_driver (&nsfont_driver, NULL);
1527   DEFSYM (Qapple, "apple");
1528   DEFSYM (Qroman, "roman");
1529   DEFSYM (Qmedium, "medium");
1530   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1531                doc: /* Internal use: maps font registry to Unicode script. */);
1533   ascii_printable = NULL;