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