Remove comment, inapplicable since 1997 (loadup no longer loads the
[emacs.git] / src / nsfont.m
blob1319a376631c8a22c8c7fb3bf9780c959f3b4403
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
23 /* This should be the first include, as it may set up #defines affecting
24    interpretation of even the system includes. */
25 #include "config.h"
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
31 #include "charset.h"
32 #include "frame.h"
33 #include "window.h"
34 #include "fontset.h"
35 #include "nsterm.h"
36 #include "frame.h"
37 #include "character.h"
38 #include "font.h"
40 /* This header is not included from GNUstep's (0.16.0) AppKit.h.  */
41 #ifdef NS_IMPL_GNUSTEP
42 #import <AppKit/NSFontDescriptor.h>
43 #endif
45 #define NSFONT_TRACE 0
47 extern Lisp_Object Qns;
48 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
49 static Lisp_Object Qapple, Qroman, Qmedium;
50 extern Lisp_Object Qappend;
51 extern int ns_antialias_text, ns_use_qd_smoothing;
52 extern float ns_antialias_threshold;
53 extern int ns_tmp_flags;
54 extern struct nsfont_info *ns_tmp_font;
56 /* font glyph and metrics caching functions, implemented at end */
57 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
58                               unsigned char block);
59 static void ns_glyph_metrics (struct nsfont_info *font_info,
60                               unsigned char block);
63 /* ==========================================================================
65     Utilities
67    ========================================================================== */
70 /* Replace spaces w/another character so emacs core font parsing routines
71    aren't thrown off. */
72 static void
73 ns_escape_name (char *name)
75   int i =0, len =strlen (name);
76   for ( ; i<len; i++)
77     if (name[i] == ' ')
78       name[i] = '_';
82 /* Reconstruct spaces in a font family name passed through emacs. */
83 static void
84 ns_unescape_name (char *name)
86   int i =0, len =strlen (name);
87   for ( ; i<len; i++)
88     if (name[i] == '_')
89       name[i] = ' ';
93 /* Extract family name from a font spec. */
94 static NSString *
95 ns_get_family (Lisp_Object font_spec)
97   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
98   if (NILP (tem))
99       return nil;
100   else
101     {
102       char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
103       NSString *family;
104       ns_unescape_name (tmp);
105       family = [NSString stringWithUTF8String: tmp];
106       free (tmp);
107       return family;
108     }
112 /* Return 0 if attr not set, else value (which might also be 0).
113    On Leopard 0 gets returned even on descriptors where the attribute
114    was never set, so there's no way to distinguish between unspecified
115    and set to not have.  Callers should assume 0 means unspecified. */
116 static float
117 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
119     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
120     NSNumber *val = [tdict objectForKey: trait];
121     return val == nil ? 0.0 : [val floatValue];
125 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
126    to NSFont descriptor.  Information under extra only needed for matching. */
127 #define STYLE_REF 100
128 static NSFontDescriptor
129 *ns_spec_to_descriptor(Lisp_Object font_spec)
131     NSFontDescriptor *fdesc;
132     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
133     NSMutableDictionary *tdict = [NSMutableDictionary new];
134     NSString *family = ns_get_family (font_spec);
135     float n;
137     /* add each attr in font_spec to fdAttrs.. */
138     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
139     if (n != -1 && n != STYLE_REF)
140         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
141                   forKey: NSFontWeightTrait];
142     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
143     if (n != -1 && n != STYLE_REF)
144         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
145                   forKey: NSFontSlantTrait];
146     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
147     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
148         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
149                   forKey: NSFontWidthTrait];
150     if ([tdict count] > 0)
151         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
153     fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
154     if (family != nil)
155         fdesc = [fdesc fontDescriptorWithFamily: family];
156     return fdesc;
160 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
161 static Lisp_Object
162 ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
164     Lisp_Object font_entity = font_make_entity ();
165     /*   NSString *psName = [desc postscriptName]; */
166     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
167     unsigned int traits = [desc symbolicTraits];
168     char *escapedFamily;
170     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
171     if (family == nil)
172       family = [desc objectForKey: NSFontNameAttribute];
173     if (family == nil)
174       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
176     escapedFamily = strdup ([family UTF8String]);
177     ns_escape_name (escapedFamily);
179     ASET (font_entity, FONT_TYPE_INDEX, Qns);
180     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
181     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
182     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
183     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
185     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
186                     traits & NSFontBoldTrait ? Qbold : Qmedium);
187 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
188                     make_number (100 + 100
189                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
190     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
191                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
192 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
193                     make_number (100 + 100
194                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
195     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
196                     traits & NSFontCondensedTrait ? Qcondensed :
197                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
198 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
199                     make_number (100 + 100
200                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
202     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
203     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
204     ASET (font_entity, FONT_SPACING_INDEX,
205           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
206               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
208     ASET (font_entity, FONT_EXTRA_INDEX, extra);
209     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
211     if (NSFONT_TRACE)
212       {
213         fprintf (stderr, "created font_entity:\n    ");
214         debug_print (font_entity);
215       }
217     free (escapedFamily);
218     return font_entity;
222 /* Default font entity. */
223 static Lisp_Object
224 ns_fallback_entity ()
226   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
227       fontDescriptor], Qnil, NULL);
231 /* Utility: get width of a char c in screen font sfont */
232 static float
233 ns_char_width (NSFont *sfont, int c)
235     float w;
236     NSString *cstr = [NSString stringWithFormat: @"%c", c];
237 #ifdef NS_IMPL_COCOA
238     NSGlyph glyph = [sfont glyphWithName: cstr];
239     if (glyph)
240       {
241         float w = [sfont advancementForGlyph: glyph].width;
242         if (w >= 1.5)
243             return w;
244       }
245 #endif
246     w = [sfont widthOfString: cstr];
247     return max (w, 2.0);
251 /* Return whether set1 covers set2 to a reasonable extent given by pct.
252    We check, out of each 16 unicode char range containing chars in set2,
253    whether at least one character is present in set1.
254    This must be true for pct of the pairs to consider it covering. */
255 static BOOL
256 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
258     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
259     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
260     int i, off = 0, tot = 0;
262     for (i=0; i<4096; i++, bytes1++, bytes2++)
263         if (*bytes2)
264           {
265             tot++;
266             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
267                 off++;
268           }
269 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
270     return (float)off / tot < 1.0 - pct;
274 /* Convert :lang property to a script.  Use of :lang property by font backend
275    seems to be limited for now (2009/05) to ja, zh, and ko. */
276 static NSString
277 *ns_lang_to_script (Lisp_Object lang)
279     if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
280         return @"han";
281     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
282              have more characters. */
283     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
284         return @"han";
285     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
286         return @"hangul";
287     else
288         return @"";
292 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
293    everyone just use some standard unicode names for these?) */
294 static NSString
295 *ns_otf_to_script (Lisp_Object otf)
297     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
298     return CONSP (script)
299         ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
300         : @"";
304 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec
305    for something that can be mapped to a unicode script.  Empty string returned
306    if no script spec found.
307    TODO: Eventually registry / encoding should be checked and mapped, but for
308    now the font backend will try script/lang/otf if registry fails, so it is
309    not needed. */
310 static NSString
311 *ns_get_req_script (Lisp_Object font_spec)
313     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
315     for ( ; CONSP (extra); extra = XCDR (extra))
316       {
317         Lisp_Object tmp = XCAR (extra);
318         if (CONSP (tmp))
319           {
320             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
321             if (EQ (key, QCscript) && SYMBOLP (val))
322                 return [NSString stringWithUTF8String:
323                             SDATA (SYMBOL_NAME (val))];
324             if (EQ (key, QClang) && SYMBOLP (val))
325                 return ns_lang_to_script (val);
326             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
327                 return ns_otf_to_script (val);
328           }
329       }
330     return @"";
334 /* This small function is static in fontset.c.  If it can be made public for
335    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
336 static void
337 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
339     if (EQ (XCAR (arg), val))
340       {
341         if (CONSP (range))
342           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
343         else
344           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
345       }
349 /* Use the unicode range information in Vchar_script_table to convert a script
350    name into an NSCharacterSet. */
351 static NSCharacterSet
352 *ns_script_to_charset (NSString *scriptName)
354     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
355     Lisp_Object script = intern ([scriptName UTF8String]);
356     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
358     if (! NILP (Fmemq (script, script_list)))
359       {
360         Lisp_Object ranges, range_list;
362         ranges = Fcons (script, Qnil);
363         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
364                         ranges);
365         range_list = Fnreverse (XCDR (ranges));
366         if (! NILP (range_list))
367           {
368             for (; CONSP (range_list); range_list = XCDR (range_list))
369               {
370                 int start = XINT (XCAR (XCAR (range_list)));
371                 int end = XINT (XCDR (XCAR (range_list)));
372                 if (NSFONT_TRACE)
373                     debug_print (XCAR (range_list));
374                 if (end < 0x10000)
375                     [charset addCharactersInRange:
376                         NSMakeRange (start, end-start)];
377               }
378           }
379       }
380     return charset;
384 /* Return an array of font families containing characters for the given
385    script, for the given coverage criterion, including at least LastResort.
386    Results are cached by script for faster access.
387    If none are found, we reduce the percentage and try again, until 5%.
388    This provides a font with at least some characters if such can be found.
389    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
390    (b) need approximate match as fonts covering full unicode ranges are rare. */
391 static NSSet
392 *ns_get_covering_families (NSString *script, float pct)
394     static NSMutableDictionary *scriptToFamilies = nil;
395     NSMutableSet *families;
397     if (NSFONT_TRACE)
398         NSLog(@"Request covering families for script: '%@'", script);
400     if (scriptToFamilies == nil)
401         scriptToFamilies = [[NSMutableDictionary alloc] init];
403     if ((families = [scriptToFamilies objectForKey: script]) == nil)
404       {
405         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
406         NSArray *allFamilies = [fontMgr availableFontFamilies];
408         if ([script length] == 0)
409             families = [NSMutableSet setWithArray: allFamilies];
410         else
411           {
412             NSCharacterSet *charset = ns_script_to_charset (script);
413             NSString *family;
414             families = [NSMutableSet setWithCapacity: 10];
415             while (1)
416               {
417                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
418                 while (family = [allFamiliesEnum nextObject])
419                   {
420                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
421                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
422                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
423                     if (fset == nil)
424                       fset = [NSCharacterSet characterSetWithRange:
425                                                NSMakeRange (0, 127)];
426                     if (ns_charset_covers(fset, charset, pct))
427                         [families addObject: family];
428                   }
429                 pct -= 0.2;
430                 if ([families count] > 0 || pct < 0.05)
431                     break;
432               }
433           }
434 #ifdef NS_IMPL_COCOA
435         if ([families count] == 0)
436             [families addObject: @"LastResort"];
437 #endif
438         [scriptToFamilies setObject: families forKey: script];
439       }
441     if (NSFONT_TRACE)
442         NSLog(@"    returning %d families", [families count]);
443     return families;
447 /* Implementation for list() and match().  List() can return nil, match()
448 must return something.  Strategy is to drop family name from attribute
449 matching set for match. */
450 static Lisp_Object
451 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
453     Lisp_Object tem, list = Qnil;
454     NSFontDescriptor *fdesc, *desc;
455     NSMutableSet *fkeys;
456     NSArray *matchingDescs;
457     NSEnumerator *dEnum;
458     NSString *family;
459     NSSet *cFamilies;
460     BOOL foundItal = NO;
462     if (NSFONT_TRACE)
463       {
464         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
465                  (isMatch ? "match" : "list"));
466         debug_print (font_spec);
467       }
469     /* If has non-unicode registry, give up. */
470     tem = AREF (font_spec, FONT_REGISTRY_INDEX);
471     if (! NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
472         return isMatch ? ns_fallback_entity () : Qnil;
474     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
476     fdesc = ns_spec_to_descriptor (font_spec);
477     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
478     if (isMatch)
479         [fkeys removeObject: NSFontFamilyAttribute];
481     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
482     if (NSFONT_TRACE)
483         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
484               [matchingDescs count]);
486     for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
487       {
488         if (![cFamilies containsObject:
489                  [desc objectForKey: NSFontFamilyAttribute]])
490             continue;
491         tem = ns_descriptor_to_entity (desc,
492                                          AREF (font_spec, FONT_EXTRA_INDEX),
493                                        NULL);
494         if (isMatch)
495           return tem;
496         list = Fcons (tem, list);
497         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
498             foundItal = YES;
499       }
501     /* Add synthItal member if needed. */
502     family = [fdesc objectForKey: NSFontFamilyAttribute];
503     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
504       {
505         NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
506             fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
507             fontDescriptorWithFamily: family];
508         list = Fcons (ns_descriptor_to_entity (sDesc,
509                                          AREF (font_spec, FONT_EXTRA_INDEX),
510                                          "synthItal"), list);
511       }
513     /* Return something if was a match and nothing found. */
514     if (isMatch)
515       return ns_fallback_entity ();
517     if (NSFONT_TRACE)
518         fprintf (stderr, "    Returning %d entities.\n", XINT (Flength (list)));
520     return list;
525 /* ==========================================================================
527     Font driver implementation
529    ========================================================================== */
532 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
533 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
534 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
535 static Lisp_Object nsfont_list_family (Lisp_Object frame);
536 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
537                                  int pixel_size);
538 static void nsfont_close (FRAME_PTR f, struct font *font);
539 static int nsfont_has_char (Lisp_Object entity, int c);
540 static unsigned int nsfont_encode_char (struct font *font, int c);
541 static int nsfont_text_extents (struct font *font, unsigned int *code,
542                                 int nglyphs, struct font_metrics *metrics);
543 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
544                         int with_background);
546 struct font_driver nsfont_driver =
547   {
548     0,                          /* Qns */
549     1,                          /* case sensitive */
550     nsfont_get_cache,
551     nsfont_list,
552     nsfont_match,
553     nsfont_list_family,
554     NULL,                       /*free_entity */
555     nsfont_open,
556     nsfont_close,
557     NULL,                       /* prepare_face */
558     NULL,                       /* done_face */
559     nsfont_has_char,
560     nsfont_encode_char,
561     nsfont_text_extents,
562     nsfont_draw,
563     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
564                  anchor_point, otf_capability, otf_driver,
565                  start_for_frame, end_for_frame, shape */
566   };
569 /* Return a cache of font-entities on FRAME.  The cache must be a
570    cons whose cdr part is the actual cache area.  */
571 static Lisp_Object
572 nsfont_get_cache (FRAME_PTR frame)
574   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
575   return (dpyinfo->name_list_element);
579 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
580    **list** of font-entities.  This and match () are sole APIs that allocate
581    font-entities.  Properties to be considered (2009/05/19) are:
582    regular: foundry, family, adstyle, registry
583    extended: script, lang, otf
584   "Extended" properties are not part of the vector but get stored as
585    lisp properties under FONT_EXTRA_INDEX.
587    The returned entities should have type set (to 'ns), plus the following:
588    foundry, family, adstyle, registry,
589    weight, slant, width, size (0 if scalable),
590    dpi, spacing, avgwidth (0 if scalable)  */
591 static Lisp_Object
592 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
594     return ns_findfonts (font_spec, NO);
598 /* Return a font entity most closely maching with FONT_SPEC on
599    FRAME.  The closeness is determined by the font backend, thus
600    `face-font-selection-order' is ignored here.
601    Properties to be considered are same as for list(). */
602 static Lisp_Object
603 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
605     return ns_findfonts(font_spec, YES);
609 /* List available families.  The value is a list of family names
610    (symbols). */
611 static Lisp_Object
612 nsfont_list_family (Lisp_Object frame)
614   Lisp_Object list = Qnil;
615   NSEnumerator *families =
616     [[[NSFontManager sharedFontManager] availableFontFamilies]
617       objectEnumerator];
618   NSString *family;
619   while (family = [families nextObject])
620       list = Fcons (intern ([family UTF8String]), list);
621   /* FIXME: escape the name? */
623   if (NSFONT_TRACE)
624     fprintf (stderr, "nsfont: list families returning %d entries\n",
625             XINT (Flength (list)));
627   return list;
631 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
632    scalable, open it with PIXEL_SIZE.  */
633 static Lisp_Object
634 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
636   BOOL synthItal;
637   unsigned int traits = 0;
638   struct nsfont_info *font_info;
639   struct font *font;
640   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
641   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
642   NSString *family;
643   NSFont *nsfont, *sfont;
644   Lisp_Object tem;
645   NSRect brect;
646   Lisp_Object font_object;
647   int i;
648   int fixLeopardBug;
649   static NSMutableDictionary *fontCache = nil;
650   NSNumber *cached;
652   /* 2008/03/08: The same font may end up being requested for different
653      entities, due to small differences in numeric values or other issues,
654      or for different copies of the same entity.  Therefore we cache to
655      avoid creating multiple struct font objects (with metrics cache, etc.)
656      for the same NSFont object. */
657   if (fontCache == nil)
658     fontCache = [[NSMutableDictionary alloc] init];
660   if (NSFONT_TRACE)
661     {
662       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
663       debug_print (font_entity);
664     }
666   if (pixel_size <= 0)
667     {
668       /* try to get it out of frame params */
669         Lisp_Object tem = get_frame_param (f, Qfontsize);
670         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
671     }
673   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
674   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
675                                        9);
676   family = ns_get_family (font_entity);
677   if (family == nil)
678     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
679   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
680      when setting family in ns_spec_to_descriptor(). */
681   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
682       traits |= NSBoldFontMask;
683   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
684       traits |= NSItalicFontMask;
686   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
687   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
688   nsfont = [fontMgr fontWithFamily: family
689                             traits: traits weight: fixLeopardBug
690                               size: pixel_size];
691   /* if didn't find, try synthetic italic */
692   if (nsfont == nil && synthItal)
693     {
694       nsfont = [fontMgr fontWithFamily: family
695                                 traits: traits & ~NSItalicFontMask
696                                 weight: fixLeopardBug size: pixel_size];
697     }
698 #ifdef NS_IMPL_COCOA
699   /* LastResort not really a family */
700   if (nsfont == nil && [@"LastResort" isEqualToString: family])
701       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
702 #endif
704   if (nsfont == nil)
705     {
706       message_with_string ("*** Warning: font in family '%s' not found",
707                           build_string ([family UTF8String]), 1);
708       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
709     }
711   if (NSFONT_TRACE)
712     NSLog (@"%@\n", nsfont);
714   /* Check the cache */
715   cached = [fontCache objectForKey: nsfont];
716   if (cached != nil && !synthItal)
717     {
718       if (NSFONT_TRACE)
719         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
720       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
721       XHASH (font_object) = [cached unsignedLongValue];
722       return font_object;
723     }
724   else
725     {
726       font_object = font_make_object (VECSIZE (struct nsfont_info),
727                                       font_entity, pixel_size);
728       if (!synthItal)
729         [fontCache setObject: [NSNumber numberWithUnsignedLong:
730                                           (unsigned long) XHASH (font_object)]
731                       forKey: nsfont];
732     }
734   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
735   font = (struct font *) font_info;
736   if (!font)
737     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
739   font_info->glyphs = (unsigned short **)
740     xmalloc (0x100 * sizeof (unsigned short *));
741   font_info->metrics = (struct font_metrics **)
742     xmalloc (0x100 * sizeof (struct font_metrics *));
743   if (!font_info->glyphs || !font_info->metrics)
744     return Qnil;
745   bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
746   bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
748   BLOCK_INPUT;
750   /* for metrics */
751   sfont = [nsfont screenFont];
752   if (sfont == nil)
753     sfont = nsfont;
755   /* non-metric backend font struct fields */
756   font = (struct font *) font_info;
757   font->pixel_size = [sfont pointSize];
758   font->driver = &nsfont_driver;
759   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
760   font->encoding_charset = -1;
761   font->repertory_charset = -1;
762   font->default_ascent = 0;
763   font->vertical_centering = 0;
764   font->baseline_offset = 0;
765   font->relative_compose = 0;
766   font->font_encoder = NULL;
768   font->props[FONT_FORMAT_INDEX] = Qns;
769   font->props[FONT_FILE_INDEX] = Qnil;
771   {
772     double expand, hshrink;
773     float full_height, min_height, hd;
774     const char *fontName = [[nsfont fontName] UTF8String];
775     int len = strlen (fontName);
777 #ifdef NS_IMPL_GNUSTEP
778     font_info->nsfont = sfont;
779 #else
780     font_info->nsfont = nsfont;
781 #endif
782     [font_info->nsfont retain];
784     /* set up ns_font (defined in nsgui.h) */
785     font_info->name = (char *)xmalloc (strlen (fontName) + 1);
786     bcopy (fontName, font_info->name, strlen (fontName) + 1);
787     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
788     font_info->ital =
789       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
791     /* Metrics etc.; some fonts return an unusually large max advance, so we
792        only use it for fonts that have wide characters. */
793     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
794       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
796     brect =  [sfont boundingRectForFont];
797     full_height = brect.size.height;
798     min_height = [sfont ascender] - [sfont descender];
799     hd = full_height - min_height;
801     /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
802     expand = 0.0;
803     hshrink = 1.0;
805     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
806     font_info->underwidth = [sfont underlineThickness];
807     font_info->size = font->pixel_size;
808     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
810     /* max bounds */
811     font_info->max_bounds.ascent =
812       lrint (hshrink * [sfont ascender] + expand * hd/2);
813     font_info->max_bounds.descent =
814       -lrint (hshrink* [sfont descender] - expand*hd/2);
815     font_info->height =
816       font_info->max_bounds.ascent + font_info->max_bounds.descent;
817     font_info->max_bounds.width = lrint (font_info->width);
818     font_info->max_bounds.lbearing = lrint (brect.origin.x);
819     font_info->max_bounds.rbearing =
820       lrint (brect.size.width - font_info->width);
822 #ifdef NS_IMPL_COCOA
823     /* set up synthItal and the CG font */
824     font_info->synthItal = synthItal;
825     {
826       ATSFontRef atsFont = ATSFontFindFromPostScriptName
827         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
829       if (atsFont == kATSFontRefUnspecified)
830         {
831           /* see if we can get it by dropping italic (then synthesizing) */
832           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
833               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
834                 fontName], kATSOptionFlagsDefault);
835           if (atsFont != kATSFontRefUnspecified)
836               font_info->synthItal = YES;
837           else
838             {
839               /* last resort fallback */
840               atsFont = ATSFontFindFromPostScriptName
841                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
842             }
843         }
844       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
845     }
846 #endif
848     /* set up metrics portion of font struct */
849     font->ascent = [sfont ascender];
850     font->descent = -[sfont descender];
851     font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
852     font->space_width = lrint (ns_char_width (sfont, ' '));
853     font->average_width = lrint (font_info->width);
854     font->max_width = lrint (font_info->max_bounds.width);
855     font->height = lrint (font_info->height);
856     font->underline_position = lrint (font_info->underpos);
857     font->underline_thickness = lrint (font_info->underwidth);
859     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
860     font->props[FONT_FULLNAME_INDEX] =
861       make_unibyte_string (font_info->name, strlen (font_info->name));
862   }
863   UNBLOCK_INPUT;
865   return font_object;
869 /* Close FONT on frame F. */
870 static void
871 nsfont_close (FRAME_PTR f, struct font *font)
873   struct nsfont_info *font_info = (struct nsfont_info *)font;
874   int i;
876   /* FIXME: this occurs apparently due to same failure to detect same font
877             that causes need for cache in nsfont_open () */
878   if (!font_info)
879       return;
881   for (i =0; i<0x100; i++)
882     {
883       xfree (font_info->glyphs[i]);
884       xfree (font_info->metrics[i]);
885     }
886   [font_info->nsfont release];
887 #ifdef NS_IMPL_COCOA
888   CGFontRelease (font_info->cgfont);
889 #endif
890   xfree (font_info->name);
891   xfree (font_info);
895 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
896    return 1.  If not, return 0.  If a font must be opened to check
897    it, return -1. */
898 static int
899 nsfont_has_char (Lisp_Object entity, int c)
901   return -1;
905 /* Return a glyph code of FONT for character C (Unicode code point).
906    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
907 static unsigned int
908 nsfont_encode_char (struct font *font, int c)
910   struct nsfont_info *font_info = (struct nsfont_info *)font;
911   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
912   unsigned short g;
914   if (c > 0xFFFF)
915     return FONT_INVALID_CODE;
917   /* did we already cache this block? */
918   if (!font_info->glyphs[high])
919     ns_uni_to_glyphs (font_info, high);
921   g = font_info->glyphs[high][low];
922   return g == 0xFFFF ? FONT_INVALID_CODE : g;
926 /* Perform the size computation of glyphs of FONT and fill in members
927    of METRICS.  The glyphs are specified by their glyph codes in
928    CODE (length NGLYPHS). */
929 static int
930 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
931                      struct font_metrics *metrics)
933   struct nsfont_info *font_info = (struct nsfont_info *)font;
934   struct font_metrics *pcm;
935   unsigned char high, low;
936   int totalWidth = 0;
937   int i;
939   bzero (metrics, sizeof (struct font_metrics));
941   for (i =0; i<nglyphs; i++)
942     {
943       /* get metrics for this glyph, filling cache if need be */
944       /* TODO: get metrics for whole string from an NSLayoutManager
945                (if not too slow) */
946       high = (code[i] & 0xFF00) >> 8;
947       low = code[i] & 0x00FF;
948       if (!font_info->metrics[high])
949         ns_glyph_metrics (font_info, high);
950       pcm = &(font_info->metrics[high][low]);
952       if (metrics->lbearing > totalWidth + pcm->lbearing)
953         metrics->lbearing = totalWidth + pcm->lbearing;
954       if (metrics->rbearing < totalWidth + pcm->rbearing)
955         metrics->rbearing = totalWidth + pcm->rbearing;
956       if (metrics->ascent < pcm->ascent)
957         metrics->ascent = pcm->ascent;
958       if (metrics->descent < pcm->descent)
959         metrics->descent = pcm->descent;
961       totalWidth += pcm->width;
962     }
964   metrics->width = totalWidth;
966   return totalWidth; /* not specified in doc, but xfont.c does it */
970 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
971    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
972    is nonzero, fill the background in advance.  It is assured that
973    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
974 static int
975 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
976              int with_background)
977 /* NOTE: focus and clip must be set
978      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
980   static char cbuf[1024];
981   char *c = cbuf;
982 #ifdef NS_IMPL_GNUSTEP
983   static float advances[1024];
984   float *adv = advances;
985 #else
986   static CGSize advances[1024];
987   CGSize *adv = advances;
988 #endif
989   struct face *face;
990   NSRect r;
991   struct nsfont_info *font = ns_tmp_font;
992   NSColor *col, *bgCol;
993   unsigned short *t = s->char2b;
994   int i, len;
995   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
996   int end = isComposite ? s->cmp_to : s->nchars;
998   /* Select face based on input flags */
999   switch (ns_tmp_flags)
1000     {
1001     case NS_DUMPGLYPH_CURSOR:
1002       face = s->face;
1003       break;
1004     case NS_DUMPGLYPH_MOUSEFACE:
1005       face = FACE_FROM_ID (s->f,
1006                            FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1007       if (!face)
1008         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1009       break;
1010     default:
1011       face = s->face;
1012     }
1014   r.origin.x = s->x;
1015   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1016     r.origin.x += abs (s->face->box_line_width);
1018   r.origin.y = s->y;
1019   r.size.height = FONT_HEIGHT (font);
1021   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1022      NS to render the string, it will come out differently from the individual
1023      character widths added up because of layout processing. */
1024   {
1025     XCharStruct *cs;
1026     int cwidth, twidth = 0;
1027     int hi, lo;
1028     /* FIXME: composition: no vertical displacement is considered. */
1029     t += s->cmp_from; /* advance into composition */
1030     for (i = s->cmp_from; i < end; i++, t++)
1031       {
1032         hi = (*t & 0xFF00) >> 8;
1033         lo = *t & 0x00FF;
1034         if (isComposite)
1035           {
1036             if (!s->first_glyph->u.cmp.automatic)
1037                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1038             else
1039               {
1040                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1041                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1042                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1043                     cwidth = LGLYPH_WIDTH (glyph);
1044                 else
1045                   {
1046                     cwidth = LGLYPH_WADJUST (glyph);
1047 #ifdef NS_IMPL_GNUSTEP
1048                     *(adv-1) += LGLYPH_XOFF (glyph);
1049 #else
1050                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1051 #endif
1052                   }
1053               }
1054           }
1055         else
1056           {
1057             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1058               ns_glyph_metrics (font, hi);
1059             cwidth = font->metrics[hi][lo].width;
1060           }
1061         twidth += cwidth;
1062 #ifdef NS_IMPL_GNUSTEP
1063         *adv++ = cwidth;
1064         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1065 #else
1066         (*adv++).width = cwidth;
1067 #endif
1068       }
1069     len = adv - advances;
1070     r.size.width = twidth;
1071     *c = 0;
1072   }
1074   /* fill background if requested */
1075   if (with_background && !isComposite)
1076     {
1077       NSRect br = r;
1078       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1079       int mbox_line_width = max (s->face->box_line_width, 0);
1081       if (s->row->full_width_p)
1082         {
1083           if (br.origin.x <= fibw + 1 + mbox_line_width)
1084             {
1085               br.size.width += br.origin.x - mbox_line_width;
1086               br.origin.x = mbox_line_width;
1087             }
1088           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1089                 <= fibw+1)
1090             br.size.width += fibw;
1091         }
1092       if (s->face->box == FACE_NO_BOX)
1093         {
1094           /* expand unboxed top row over internal border */
1095           if (br.origin.y <= fibw + 1 + mbox_line_width)
1096             {
1097               br.size.height += br.origin.y;
1098               br.origin.y = 0;
1099             }
1100         }
1101       else
1102         {
1103           int correction = abs (s->face->box_line_width)+1;
1104           br.origin.y += correction;
1105           br.size.height -= 2*correction;
1106           br.origin.x += correction;
1107           br.size.width -= 2*correction;
1108         }
1110       if (!s->face->stipple)
1111         [(NS_FACE_BACKGROUND (face) != 0
1112           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1113           : FRAME_BACKGROUND_COLOR (s->f)) set];
1114       else
1115         {
1116           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1117           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1118         }
1119       NSRectFill (br);
1120     }
1123   /* set up for character rendering */
1124   r.origin.y += font->voffset + (s->height - font->height)/2;
1126   col = (NS_FACE_FOREGROUND (face) != 0
1127          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1128          : FRAME_FOREGROUND_COLOR (s->f));
1129   /* FIXME: find another way to pass this */
1130   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1131            : (NS_FACE_BACKGROUND (face) != 0
1132               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1133               : FRAME_BACKGROUND_COLOR (s->f)));
1135   /* render under GNUstep using DPS */
1136 #ifdef NS_IMPL_GNUSTEP
1137   {
1138     NSGraphicsContext *context = GSCurrentContext ();
1140     DPSgsave (context);
1141     [font->nsfont set];
1143     /* do erase if "foreground" mode */
1144     if (bgCol != nil)
1145       {
1146         [bgCol set];
1147         DPSmoveto (context, r.origin.x, r.origin.y);
1148 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1149         DPSxshow (context, cbuf, advances, len);
1150         DPSstroke (context);
1151         [col set];
1152 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1153       }
1155     /* do underline */
1156     if (face->underline_p)
1157       {
1158         if (face->underline_color != 0)
1159           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1160         else
1161           [col set];
1162         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1163         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1164         if (face->underline_color != 0)
1165           [col set];
1166       }
1167     else
1168       [col set];
1170     /* draw with DPSxshow () */
1171     DPSmoveto (context, r.origin.x, r.origin.y);
1172     DPSxshow (context, cbuf, advances, len);
1173     DPSstroke (context);
1175     DPSgrestore (context);
1176     return to-from;
1177   }
1179 #else  /* NS_IMPL_COCOA */
1180   {
1181     CGContextRef gcontext =
1182       [[NSGraphicsContext currentContext] graphicsPort];
1183     static CGAffineTransform fliptf;
1184     static BOOL firstTime = YES;
1186     if (firstTime)
1187       {
1188         firstTime = NO;
1189         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1190       }
1192     CGContextSaveGState (gcontext);
1194     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1196     CGContextSetFont (gcontext, font->cgfont);
1197     CGContextSetFontSize (gcontext, font->size);
1198     if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1199       CGContextSetShouldAntialias (gcontext, 0);
1200     else
1201       CGContextSetShouldAntialias (gcontext, 1);
1202     if (EQ (ns_use_qd_smoothing, Qt))
1203       CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1205     CGContextSetTextMatrix (gcontext, fliptf);
1207     if (bgCol != nil)
1208       {
1209         /* foreground drawing; erase first to avoid overstrike */
1210         [bgCol set];
1211         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1212         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1213         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1214         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1215       }
1217     if (face->underline_p)
1218       {
1219         if (face->underline_color != 0)
1220           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1221         else
1222           [col set];
1223         CGContextBeginPath (gcontext);
1224         CGContextMoveToPoint (gcontext,
1225                               r.origin.x, r.origin.y + font->underpos);
1226         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1227                                 r.origin.y + font->underpos);
1228         CGContextStrokePath (gcontext);
1229         if (face->underline_color != 0)
1230           [col set];
1231       }
1232     else
1233       [col set];
1235     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1236     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1237                                     advances, len);
1239     if (face->overstrike)
1240       {
1241         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1242         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1243                                         advances, len);
1244       }
1246     CGContextRestoreGState (gcontext);
1247     return;
1248   }
1249 #endif  /* NS_IMPL_COCOA */
1255 /* ==========================================================================
1257     Font glyph and metrics caching functions
1259    ========================================================================== */
1261 /* Find and cache corresponding glyph codes for unicode values in given
1262    hi-byte block of 256. */
1263 static void
1264 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1266 #ifdef NS_IMPL_COCOA
1267   static EmacsGlyphStorage *glyphStorage;
1268   static char firstTime = 1;
1269 #endif
1270   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1271   unsigned int i, g, idx;
1272   unsigned short *glyphs;
1274   if (NSFONT_TRACE)
1275     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1276             font_info, block);
1278  BLOCK_INPUT;
1280 #ifdef NS_IMPL_COCOA
1281   if (firstTime)
1282     {
1283       firstTime = 0;
1284       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1285     }
1286 #endif
1288   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1289   if (!unichars || !(font_info->glyphs[block]))
1290     abort ();
1292   /* create a string containing all unicode characters in this block */
1293   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1294     if (idx < 0xD800 || idx > 0xDFFF)
1295       unichars[i] = idx;
1296     else
1297       unichars[i] = 0xFEFF;
1298   unichars[0x100] = 0;
1300   {
1301 #ifdef NS_IMPL_COCOA
1302     NSString *allChars = [[NSString alloc]
1303                                initWithCharactersNoCopy: unichars
1304                                                  length: 0x100
1305                                            freeWhenDone: NO];
1306     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1307     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1308     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1309     unsigned int gInd =0, cInd =0;
1311     [glyphStorage setString: allChars font: font_info->nsfont];
1312     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1313                         desiredNumberOfCharacters: glyphStorage->maxChar
1314                                        glyphIndex: &gInd characterIndex: &cInd];
1315 #endif
1316     glyphs = font_info->glyphs[block];
1317     for (i =0; i<0x100; i++, glyphs++)
1318       {
1319 #ifdef NS_IMPL_GNUSTEP
1320         g = unichars[i];
1321 #else
1322         g = glyphStorage->cglyphs[i];
1323         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1324         if (g > numGlyphs)
1325           g = 0xFFFF; /* hopefully unused... */
1326 #endif
1327         *glyphs = g;
1328       }
1330 #ifdef NS_IMPL_COCOA
1331     [allChars release];
1332 #endif
1333   }
1335   UNBLOCK_INPUT;
1336   xfree (unichars);
1340 /* Determine and cache metrics for corresponding glyph codes in given
1341    hi-byte block of 256. */
1342 static void
1343 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1345   unsigned int i, g;
1346   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1347   NSFont *sfont;
1348   struct font_metrics *metrics;
1350   if (NSFONT_TRACE)
1351     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1352             font_info, block);
1354 #ifdef NS_IMPL_GNUSTEP
1355   /* not implemented yet (as of startup 0.18), so punt */
1356   if (numGlyphs == 0)
1357     numGlyphs = 0x10000;
1358 #endif
1360  BLOCK_INPUT;
1361  sfont = [font_info->nsfont screenFont];
1363   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1364   bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1365   if (!(font_info->metrics[block]))
1366     abort ();
1368   metrics = font_info->metrics[block];
1369   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1370     {
1371       float w, lb, rb;
1372       NSRect r = [sfont boundingRectForGlyph: g];
1374 #ifdef NS_IMPL_GNUSTEP
1375       {
1376         /* lord help us */
1377         NSString *s = [NSString stringWithFormat: @"%c", g];
1378         w = [sfont widthOfString: s];
1379       }
1380 #else
1381       w = [sfont advancementForGlyph: g].width;
1382 #endif
1383       w = max (w, 2.0);
1384       metrics->width = lrint (w);
1386       lb = r.origin.x;
1387       rb = r.size.width - w;
1388       if (lb < 0)
1389         metrics->lbearing = round (lb);
1390       if (font_info->ital)
1391         rb += 0.22 * font_info->height;
1392       metrics->rbearing = lrint (w + rb);
1394       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1395  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1396       metrics->ascent = r.size.height - metrics->descent;
1397 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1398     }
1399   UNBLOCK_INPUT;
1403 #ifdef NS_IMPL_COCOA
1404 /* helper for font glyph setup */
1405 @implementation EmacsGlyphStorage
1407 - init
1409   return [self initWithCapacity: 1024];
1412 - initWithCapacity: (unsigned long) c
1414   self = [super init];
1415   maxChar = 0;
1416   maxGlyph = 0;
1417   dict = [NSMutableDictionary new];
1418   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1419   return self;
1422 - (void) dealloc
1424   if (attrStr != nil)
1425     [attrStr release];
1426   [dict release];
1427   xfree (cglyphs);
1428   [super dealloc];
1431 - (void) setString: (NSString *)str font: (NSFont *)font
1433   [dict setObject: font forKey: NSFontAttributeName];
1434   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1435   maxChar = [str length];
1436   maxGlyph = 0;
1439 /* NSGlyphStorage protocol */
1440 - (unsigned int)layoutOptions
1442   return 0;
1445 - (NSAttributedString *)attributedString
1447   return attrStr;
1450 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1451         forStartingGlyphAtIndex: (unsigned int)glyphIndex
1452         characterIndex: (unsigned int)charIndex
1454   len = glyphIndex+length;
1455   for (i =glyphIndex; i<len; i++)
1456     cglyphs[i] = glyphs[i-glyphIndex];
1457   if (len > maxGlyph)
1458     maxGlyph = len;
1461 - (void)setIntAttribute: (int)attributeTag value: (int)val
1462         forGlyphAtIndex: (unsigned)glyphIndex
1464   return;
1467 @end
1468 #endif /* NS_IMPL_COCOA */
1471 /* Debugging */
1472 void
1473 ns_dump_glyphstring (struct glyph_string *s)
1475   int i;
1477   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1478 "overlap = %d, bg_filled = %d:",
1479            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1480            s->row->overlapping_p, s->background_filled_p);
1481   for (i =0; i<s->nchars; i++)
1482     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1483   fprintf (stderr, "\n");
1487 void
1488 syms_of_nsfont ()
1490   nsfont_driver.type = Qns;
1491   register_font_driver (&nsfont_driver, NULL);
1492   DEFSYM (Qapple, "apple");
1493   DEFSYM (Qroman, "roman");
1494   DEFSYM (Qmedium, "medium");
1497 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae