(vc-default-revision-granularity): Remove to let the normal
[emacs.git] / src / nsfont.m
blob68ed1e6dd360f3a91afa97f3b350900d2c1405f4
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 #define NSFONT_TRACE 0
42 extern Lisp_Object Qns;
43 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
44 static Lisp_Object Qapple, Qroman, Qmedium;
45 extern Lisp_Object Qappend;
46 extern int ns_antialias_text, ns_use_qd_smoothing;
47 extern float ns_antialias_threshold;
48 extern int ns_tmp_flags;
49 extern struct nsfont_info *ns_tmp_font;
51 /* font glyph and metrics caching functions, implemented at end */
52 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
53                               unsigned char block);
54 static void ns_glyph_metrics (struct nsfont_info *font_info,
55                               unsigned char block);
58 /* ==========================================================================
60     Utilities
62    ========================================================================== */
65 /* Replace spaces w/another character so emacs core font parsing routines
66    aren't thrown off. */
67 static void
68 ns_escape_name (char *name)
70   int i =0, len =strlen (name);
71   for ( ; i<len; i++)
72     if (name[i] == ' ')
73       name[i] = '_';
77 /* Reconstruct spaces in a font family name passed through emacs. */
78 static void
79 ns_unescape_name (char *name)
81   int i =0, len =strlen (name);
82   for ( ; i<len; i++)
83     if (name[i] == '_')
84       name[i] = ' ';
88 /* Extract family name from a font spec. */
89 static NSString *
90 ns_get_family (Lisp_Object font_spec)
92   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
93   if (NILP (tem))
94       return nil;
95   else
96     {
97       char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
98       NSString *family;
99       ns_unescape_name (tmp);
100       /* For names hard-coded into emacs, like 'helvetica' for splash. */
101       tmp[0] = toupper (tmp[0]);
102       family = [NSString stringWithUTF8String: tmp];
103       free (tmp);
104       return family;
105     }
109 /* Return 0 if attr not set, else value (which might also be 0).
110    On Leopard 0 gets returned even on descriptors where the attribute
111    was never set, so there's no way to distinguish between unspecified
112    and set to not have.  Callers should assume 0 means unspecified. */
113 static float
114 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
116     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
117     NSNumber *val = [tdict objectForKey: trait];
118     return val == nil ? 0.0 : [val floatValue];
122 /* Return whether font has attribute set to non-standard value. */
123 static BOOL
124 ns_has_attribute (NSFontDescriptor *fdesc, NSString *trait)
126     float v = ns_attribute_fvalue (fdesc, trait);
127     return v < -0.05 || v > 0.05;
131 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
132    to NSFont descriptor.  Information under extra only needed for matching. */
133 #define STYLE_REF 100
134 static NSFontDescriptor
135 *ns_spec_to_descriptor(Lisp_Object font_spec)
137     NSFontDescriptor *fdesc;
138     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
139     NSMutableDictionary *tdict = [NSMutableDictionary new];
140     NSString *family = ns_get_family (font_spec);
141     float n;
143     /* add each attr in font_spec to fdAttrs.. */
144     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
145     if (n != -1 && n != STYLE_REF)
146         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
147                   forKey: NSFontWeightTrait];
148     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
149     if (n != -1 && n != STYLE_REF)
150         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
151                   forKey: NSFontSlantTrait];
152     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
153     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
154         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
155                   forKey: NSFontWidthTrait];
156     if ([tdict count] > 0)
157         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
159     fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
160     if (family != nil)
161         fdesc = [fdesc fontDescriptorWithFamily: family];
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, Lisp_Object extra, char *style)
170     Lisp_Object font_entity = font_make_entity ();
171     /*   NSString *psName = [desc postscriptName]; */
172     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
173     char *escapedFamily = strdup ([family UTF8String]);
174     unsigned int traits = [desc symbolicTraits];
176     ns_escape_name (escapedFamily);
178     ASET (font_entity, FONT_TYPE_INDEX, Qns);
179     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
180     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
181     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
182     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
184     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
185                     traits & NSFontBoldTrait ? Qbold : Qmedium);
186 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
187                     make_number (100 + 100
188                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
189     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
190                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
191 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
192                     make_number (100 + 100
193                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
194     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
195                     traits & NSFontCondensedTrait ? Qcondensed :
196                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
197 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
198                     make_number (100 + 100
199                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
201     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
202     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
203     ASET (font_entity, FONT_SPACING_INDEX,
204           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
205               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
207     ASET (font_entity, FONT_EXTRA_INDEX, extra);
208     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
210     if (NSFONT_TRACE)
211       {
212         fprintf (stderr, "created font_entity:\n    ");
213         debug_print (font_entity);
214       }
216     free (escapedFamily);
217     return font_entity;
221 /* Default font entity. */
222 static Lisp_Object
223 ns_fallback_entity ()
225   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
226       fontDescriptor], Qnil, NULL);
230 /* Utility: get width of a char c in screen font sfont */
231 static float
232 ns_char_width (NSFont *sfont, int c)
234     float w;
235     NSString *cstr = [NSString stringWithFormat: @"%c", c];
236 #ifdef NS_IMPL_COCOA
237     NSGlyph glyph = [sfont glyphWithName: cstr];
238     if (glyph)
239       {
240         float w = [sfont advancementForGlyph: glyph].width;
241         if (w >= 1.5)
242             return w;
243       }
244 #endif
245     w = [sfont widthOfString: cstr];
246     return max (w, 2.0);
250 /* Return whether set1 covers set2 to a reasonable extent given by pct.
251    We check, out of each 16 unicode char range containing chars in set2,
252    whether at least one character is present in set1.
253    This must be true for pct of the pairs to consider it covering. */
254 static BOOL
255 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
257     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
258     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
259     int i, off = 0, tot = 0;
261     for (i=0; i<4096; i++, bytes1++, bytes2++)
262         if (*bytes2)
263           {
264             tot++;
265             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
266                 off++;
267           }
268 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
269     return (float)off / tot < 1.0 - pct;
273 /* Convert :lang property to a script.  Use of :lang property by font backend
274    seems to be limited for now (2009/05) to ja, zh, and ko. */
275 static NSString
276 *ns_lang_to_script (Lisp_Object lang)
278     if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
279         return @"han";
280     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
281              have more characters. */
282     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
283         return @"han";
284     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
285         return @"hangul";
286     else
287         return @"";
291 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
292    everyone just use some standard unicode names for these?) */
293 static NSString
294 *ns_otf_to_script (Lisp_Object otf)
296     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
297     return CONSP (script)
298         ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
299         : @"";
303 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec
304    for something that can be mapped to a unicode script.  Empty string returned
305    if no script spec found.
306    TODO: Eventually registry / encoding should be checked and mapped, but for
307    now the font backend will try script/lang/otf if registry fails, so it is
308    not needed. */
309 static NSString
310 *ns_get_req_script (Lisp_Object font_spec)
312     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
314     for ( ; CONSP (extra); extra = XCDR (extra))
315       {
316         Lisp_Object tmp = XCAR (extra);
317         if (CONSP (tmp))
318           {
319             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
320             if (EQ (key, QCscript) && SYMBOLP (val))
321                 return [NSString stringWithUTF8String:
322                             SDATA (SYMBOL_NAME (val))];
323             if (EQ (key, QClang) && SYMBOLP (val))
324                 return ns_lang_to_script (val);
325             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
326                 return ns_otf_to_script (val);
327           }
328       }
329     return @"";
333 /* This small function is static in fontset.c.  If it can be made public for
334    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
335 static void
336 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
338     if (EQ (XCAR (arg), val))
339       {
340         if (CONSP (range))
341           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
342         else
343           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
344       }
348 /* Use the unicode range information in Vchar_script_table to convert a script
349    name into an NSCharacterSet. */
350 static NSCharacterSet
351 *ns_script_to_charset (NSString *scriptName)
353     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
354     Lisp_Object script = intern ([scriptName UTF8String]);
355     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
357     if (! NILP (Fmemq (script, script_list)))
358       {
359         Lisp_Object ranges, range_list;
361         ranges = Fcons (script, Qnil);
362         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
363                         ranges);
364         range_list = Fnreverse (XCDR (ranges));
365         if (! NILP (range_list))
366           {
367             for (; CONSP (range_list); range_list = XCDR (range_list))
368               {
369                 int start = XINT (XCAR (XCAR (range_list)));
370                 int end = XINT (XCDR (XCAR (range_list)));
371                 if (NSFONT_TRACE)
372                     debug_print (XCAR (range_list));
373                 if (end < 0x10000)
374                     [charset addCharactersInRange:
375                         NSMakeRange (start, end-start)];
376               }
377           }
378       }
379     return charset;
383 /* Return an array of font families containing characters for the given
384    script, for the given coverage criterion, including at least LastResort.
385    Results are cached by script for faster access.
386    If none are found, we reduce the percentage and try again, until 5%.
387    This provides a font with at least some characters if such can be found.
388    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
389    (b) need approximate match as fonts covering full unicode ranges are rare. */
390 static NSSet
391 *ns_get_covering_families (NSString *script, float pct)
393     static NSMutableDictionary *scriptToFamilies = nil;
394     NSMutableSet *families;
396     if (NSFONT_TRACE)
397         NSLog(@"Request covering families for script: '%@'", script);
399     if (scriptToFamilies == nil)
400         scriptToFamilies = [[NSMutableDictionary alloc] init];
402     if ((families = [scriptToFamilies objectForKey: script]) == nil)
403       {
404         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
405         NSArray *allFamilies = [fontMgr availableFontFamilies];
407         if ([script length] == 0)
408             families = [NSMutableSet setWithArray: allFamilies];
409         else
410           {
411             NSCharacterSet *charset = ns_script_to_charset (script);
412             NSString *family;
413             families = [NSMutableSet setWithCapacity: 10];
414             while (1)
415               {
416                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
417                 while (family = [allFamiliesEnum nextObject])
418                   {
419                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
420                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
421                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
422                     if (fset == nil)
423                       fset = [NSCharacterSet characterSetWithRange:
424                                                NSMakeRange (0, 127)];
425                     if (ns_charset_covers(fset, charset, pct))
426                         [families addObject: family];
427                   }
428                 pct -= 0.2;
429                 if ([families count] > 0 || pct < 0.05)
430                     break;
431               }
432           }
433 #ifdef NS_IMPL_COCOA
434         if ([families count] == 0)
435             [families addObject: @"LastResort"];
436 #endif
437         [scriptToFamilies setObject: families forKey: script];
438       }
440     if (NSFONT_TRACE)
441         NSLog(@"    returning %d families", [families count]);
442     return families;
446 /* Implementation for list() and match().  List() can return nil, match()
447 must return something.  Strategy is to drop family name from attribute
448 matching set for match. */
449 static Lisp_Object
450 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
452     Lisp_Object tem, list = Qnil;
453     NSFontDescriptor *fdesc, *desc;
454     NSMutableSet *fkeys;
455     NSArray *matchingDescs;
456     NSEnumerator *dEnum;
457     NSString *family;
458     NSSet *cFamilies;
459     BOOL foundItal = NO;
461     if (NSFONT_TRACE)
462       {
463         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
464                  (isMatch ? "match" : "list"));
465         debug_print (font_spec);
466       }
468     /* If has non-unicode registry, give up. */
469     tem = AREF (font_spec, FONT_REGISTRY_INDEX);
470     if (! NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
471         return isMatch ? ns_fallback_entity () : Qnil;
473     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
475     fdesc = ns_spec_to_descriptor (font_spec);
476     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
477     if (isMatch)
478         [fkeys removeObject: NSFontFamilyAttribute];
480     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
481     if (NSFONT_TRACE)
482         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
483               [matchingDescs count]);
485     for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
486       {
487         if (![cFamilies containsObject:
488                  [desc objectForKey: NSFontFamilyAttribute]])
489             continue;
490         list = Fcons (ns_descriptor_to_entity (desc,
491                                          AREF (font_spec, FONT_EXTRA_INDEX),
492                                          NULL), list);
493         if (ns_has_attribute (desc, NSFontSlantTrait))
494             foundItal = YES;
495       }
497     /* Add synthItal member if needed. */
498     family = [fdesc objectForKey: NSFontFamilyAttribute];
499     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
500       {
501         NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
502             fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
503             fontDescriptorWithFamily: family];
504         list = Fcons (ns_descriptor_to_entity (sDesc,
505                                          AREF (font_spec, FONT_EXTRA_INDEX),
506                                          "synthItal"), list);
507       }
509     if (NSFONT_TRACE)
510         fprintf (stderr, "    Returning %d entities.\n", XINT (Flength (list)));
512     return list;
517 /* ==========================================================================
519     Font driver implementation
521    ========================================================================== */
524 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
525 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
526 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
527 static Lisp_Object nsfont_list_family (Lisp_Object frame);
528 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
529                                  int pixel_size);
530 static void nsfont_close (FRAME_PTR f, struct font *font);
531 static int nsfont_has_char (Lisp_Object entity, int c);
532 static unsigned int nsfont_encode_char (struct font *font, int c);
533 static int nsfont_text_extents (struct font *font, unsigned int *code,
534                                 int nglyphs, struct font_metrics *metrics);
535 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
536                         int with_background);
538 struct font_driver nsfont_driver =
539   {
540     0,                          /* Qns */
541     1,                          /* case sensitive */
542     nsfont_get_cache,
543     nsfont_list,
544     nsfont_match,
545     nsfont_list_family,
546     NULL,                       /*free_entity */
547     nsfont_open,
548     nsfont_close,
549     NULL,                       /* prepare_face */
550     NULL,                       /* done_face */
551     nsfont_has_char,
552     nsfont_encode_char,
553     nsfont_text_extents,
554     nsfont_draw,
555     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
556                  anchor_point, otf_capability, otf_driver,
557                  start_for_frame, end_for_frame, shape */
558   };
561 /* Return a cache of font-entities on FRAME.  The cache must be a
562    cons whose cdr part is the actual cache area.  */
563 static Lisp_Object
564 nsfont_get_cache (FRAME_PTR frame)
566   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
567   return (dpyinfo->name_list_element);
571 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
572    **list** of font-entities.  This and match () are sole APIs that allocate
573    font-entities.  Properties to be considered (2009/05/19) are:
574    regular: foundry, family, adstyle, registry
575    extended: script, lang, otf
576   "Extended" properties are not part of the vector but get stored as
577    lisp properties under FONT_EXTRA_INDEX.
579    The returned entities should have type set (to 'ns), plus the following:
580    foundry, family, adstyle, registry,
581    weight, slant, width, size (0 if scalable),
582    dpi, spacing, avgwidth (0 if scalable)  */
583 static Lisp_Object
584 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
586     return ns_findfonts (font_spec, NO);
590 /* Return a font entity most closely maching with FONT_SPEC on
591    FRAME.  The closeness is determined by the font backend, thus
592    `face-font-selection-order' is ignored here.
593    Properties to be considered are same as for list(). */
594 static Lisp_Object
595 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
597     return ns_findfonts(font_spec, YES);
601 /* List available families.  The value is a list of family names
602    (symbols). */
603 static Lisp_Object
604 nsfont_list_family (Lisp_Object frame)
606   Lisp_Object list = Qnil;
607   NSEnumerator *families =
608     [[[NSFontManager sharedFontManager] availableFontFamilies]
609       objectEnumerator];
610   NSString *family;
611   while (family = [families nextObject])
612       list = Fcons (intern ([family UTF8String]), list);
613   /* FIXME: escape the name? */
615   if (NSFONT_TRACE)
616     fprintf (stderr, "nsfont: list families returning %d entries\n",
617             XINT (Flength (list)));
619   return list;
623 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
624    scalable, open it with PIXEL_SIZE.  */
625 static Lisp_Object
626 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
628   BOOL synthItal;
629   unsigned int traits = 0;
630   struct nsfont_info *font_info;
631   struct font *font;
632   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
633   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
634   NSString *family;
635   NSFont *nsfont, *sfont;
636   Lisp_Object tem;
637   NSRect brect;
638   Lisp_Object font_object;
639   int i;
640   int fixLeopardBug;
641   static NSMutableDictionary *fontCache = nil;
642   NSNumber *cached;
644   /* 2008/03/08: The same font may end up being requested for different
645      entities, due to small differences in numeric values or other issues,
646      or for different copies of the same entity.  Therefore we cache to
647      avoid creating multiple struct font objects (with metrics cache, etc.)
648      for the same NSFont object. */
649   if (fontCache == nil)
650     fontCache = [[NSMutableDictionary alloc] init];
652   if (NSFONT_TRACE)
653     {
654       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
655       debug_print (font_entity);
656     }
658   if (pixel_size <= 0)
659     {
660       /* try to get it out of frame params */
661         Lisp_Object tem = get_frame_param (f, Qfontsize);
662         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
663     }
665   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
666   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
667                                        9);
668   family = ns_get_family (font_entity);
669   if (ns_has_attribute (fontDesc, NSFontWeightTrait))
670       traits |= NSBoldFontMask;
671   if (ns_has_attribute (fontDesc, NSFontSlantTrait))
672       traits |= NSItalicFontMask;
674   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
675   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
676   nsfont = [fontMgr fontWithFamily: family
677                             traits: traits weight: fixLeopardBug
678                               size: pixel_size];
679   /* if didn't find, try synthetic italic */
680   if (nsfont == nil && synthItal)
681     {
682       nsfont = [fontMgr fontWithFamily: family
683                                 traits: traits & ~NSItalicFontMask
684                                 weight: fixLeopardBug size: pixel_size];
685     }
686 #ifdef NS_IMPL_COCOA
687   /* LastResort not really a family */
688   if (nsfont == nil && [@"LastResort" isEqualToString: family])
689       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
690 #endif
692   if (nsfont == nil)
693     {
694       message_with_string ("*** Warning: font in family '%s' not found",
695                           build_string ([family UTF8String]), 1);
696       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
697     }
699   if (NSFONT_TRACE)
700     NSLog (@"%@\n", nsfont);
702   /* Check the cache */
703   cached = [fontCache objectForKey: nsfont];
704   if (cached != nil && !synthItal)
705     {
706       if (NSFONT_TRACE)
707         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
708       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
709       XHASH (font_object) = [cached unsignedLongValue];
710       return font_object;
711     }
712   else
713     {
714       font_object = font_make_object (VECSIZE (struct nsfont_info),
715                                       font_entity, pixel_size);
716       if (!synthItal)
717         [fontCache setObject: [NSNumber numberWithUnsignedLong:
718                                           (unsigned long) XHASH (font_object)]
719                       forKey: nsfont];
720     }
722   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
723   font = (struct font *) font_info;
724   if (!font)
725     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
727   font_info->glyphs = (unsigned short **)
728     xmalloc (0x100 * sizeof (unsigned short *));
729   font_info->metrics = (struct font_metrics **)
730     xmalloc (0x100 * sizeof (struct font_metrics *));
731   if (!font_info->glyphs || !font_info->metrics)
732     return Qnil;
733   bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
734   bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
736   BLOCK_INPUT;
738   /* for metrics */
739   sfont = [nsfont screenFont];
740   if (sfont == nil)
741     sfont = nsfont;
743   /* non-metric backend font struct fields */
744   font = (struct font *) font_info;
745   font->pixel_size = [sfont pointSize];
746   font->driver = &nsfont_driver;
747   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
748   font->encoding_charset = -1;
749   font->repertory_charset = -1;
750   font->default_ascent = 0;
751   font->vertical_centering = 0;
752   font->baseline_offset = 0;
753   font->relative_compose = 0;
754   font->font_encoder = NULL;
756   font->props[FONT_FORMAT_INDEX] = Qns;
757   font->props[FONT_FILE_INDEX] = Qnil;
759   {
760     double expand, hshrink;
761     float full_height, min_height, hd;
762     const char *fontName = [[nsfont fontName] UTF8String];
763     int len = strlen (fontName);
765 #ifdef NS_IMPL_GNUSTEP
766     font_info->nsfont = sfont;
767 #else
768     font_info->nsfont = nsfont;
769 #endif
770     [font_info->nsfont retain];
772     /* set up ns_font (defined in nsgui.h) */
773     font_info->name = (char *)xmalloc (strlen (fontName) + 1);
774     bcopy (fontName, font_info->name, strlen (fontName) + 1);
775     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
776     font_info->ital =
777       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
779     /* Metrics etc.; some fonts return an unusually large max advance, so we
780        only use it for fonts that have wide characters. */
781     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
782       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
784     brect =  [sfont boundingRectForFont];
785     full_height = brect.size.height;
786     min_height = [sfont ascender] - [sfont descender];
787     hd = full_height - min_height;
789     /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
790     expand = 0.0;
791     hshrink = 1.0;
793     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
794     font_info->underwidth = [sfont underlineThickness];
795     font_info->size = font->pixel_size;
796     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
798     /* max bounds */
799     font_info->max_bounds.ascent =
800       lrint (hshrink * [sfont ascender] + expand * hd/2);
801     font_info->max_bounds.descent =
802       -lrint (hshrink* [sfont descender] - expand*hd/2);
803     font_info->height =
804       font_info->max_bounds.ascent + font_info->max_bounds.descent;
805     font_info->max_bounds.width = lrint (font_info->width);
806     font_info->max_bounds.lbearing = lrint (brect.origin.x);
807     font_info->max_bounds.rbearing =
808       lrint (brect.size.width - font_info->width);
810 #ifdef NS_IMPL_COCOA
811     /* set up synthItal and the CG font */
812     font_info->synthItal = synthItal;
813     {
814       ATSFontRef atsFont = ATSFontFindFromPostScriptName
815         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
817       if (atsFont == kATSFontRefUnspecified)
818         {
819           /* see if we can get it by dropping italic (then synthesizing) */
820           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
821               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
822                 fontName], kATSOptionFlagsDefault);
823           if (atsFont != kATSFontRefUnspecified)
824               font_info->synthItal = YES;
825           else
826             {
827               /* last resort fallback */
828               atsFont = ATSFontFindFromPostScriptName
829                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
830             }
831         }
832       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
833     }
834 #endif
836     /* set up metrics portion of font struct */
837     font->ascent = [sfont ascender];
838     font->descent = -[sfont descender];
839     font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
840     font->space_width = lrint (ns_char_width (sfont, ' '));
841     font->average_width = lrint (font_info->width);
842     font->max_width = lrint (font_info->max_bounds.width);
843     font->height = lrint (font_info->height);
844     font->underline_position = lrint (font_info->underpos);
845     font->underline_thickness = lrint (font_info->underwidth);
847     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
848     font->props[FONT_FULLNAME_INDEX] =
849       make_unibyte_string (font_info->name, strlen (font_info->name));
850   }
851   UNBLOCK_INPUT;
853   return font_object;
857 /* Close FONT on frame F. */
858 static void
859 nsfont_close (FRAME_PTR f, struct font *font)
861   struct nsfont_info *font_info = (struct nsfont_info *)font;
862   int i;
864   /* FIXME: this occurs apparently due to same failure to detect same font
865             that causes need for cache in nsfont_open () */
866   if (!font_info)
867       return;
869   for (i =0; i<0x100; i++)
870     {
871       if (font_info->glyphs[i])
872         xfree (font_info->glyphs[i]);
873       if (font_info->metrics[i])
874         xfree (font_info->metrics[i]);
875     }
876   [font_info->nsfont release];
877 #ifdef NS_IMPL_COCOA
878   CGFontRelease (font_info->cgfont);
879 #endif
880   xfree (font_info->name);
881   xfree (font_info);
885 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
886    return 1.  If not, return 0.  If a font must be opened to check
887    it, return -1. */
888 static int
889 nsfont_has_char (Lisp_Object entity, int c)
891   return -1;
895 /* Return a glyph code of FONT for character C (Unicode code point).
896    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
897 static unsigned int
898 nsfont_encode_char (struct font *font, int c)
900   struct nsfont_info *font_info = (struct nsfont_info *)font;
901   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
902   unsigned short g;
904   if (c > 0xFFFF)
905     return FONT_INVALID_CODE;
907   /* did we already cache this block? */
908   if (!font_info->glyphs[high])
909     ns_uni_to_glyphs (font_info, high);
911   g = font_info->glyphs[high][low];
912   return g == 0xFFFF ? FONT_INVALID_CODE : g;
916 /* Perform the size computation of glyphs of FONT and fill in members
917    of METRICS.  The glyphs are specified by their glyph codes in
918    CODE (length NGLYPHS). */
919 static int
920 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
921                      struct font_metrics *metrics)
923   struct nsfont_info *font_info = (struct nsfont_info *)font;
924   struct font_metrics *pcm;
925   unsigned char high, low;
926   int totalWidth = 0;
927   int i;
929   bzero (metrics, sizeof (struct font_metrics));
931   for (i =0; i<nglyphs; i++)
932     {
933       /* get metrics for this glyph, filling cache if need be */
934       /* TODO: get metrics for whole string from an NSLayoutManager
935                (if not too slow) */
936       high = (code[i] & 0xFF00) >> 8;
937       low = code[i] & 0x00FF;
938       if (!font_info->metrics[high])
939         ns_glyph_metrics (font_info, high);
940       pcm = &(font_info->metrics[high][low]);
942       if (metrics->lbearing > totalWidth + pcm->lbearing)
943         metrics->lbearing = totalWidth + pcm->lbearing;
944       if (metrics->rbearing < totalWidth + pcm->rbearing)
945         metrics->rbearing = totalWidth + pcm->rbearing;
946       if (metrics->ascent < pcm->ascent)
947         metrics->ascent = pcm->ascent;
948       if (metrics->descent < pcm->descent)
949         metrics->descent = pcm->descent;
951       totalWidth += pcm->width;
952     }
954   metrics->width = totalWidth;
956   return totalWidth; /* not specified in doc, but xfont.c does it */
960 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
961    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
962    is nonzero, fill the background in advance.  It is assured that
963    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
964 static int
965 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
966              int with_background)
967 /* NOTE: focus and clip must be set
968      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
970   static char cbuf[1024];
971   char *c = cbuf;
972 #ifdef NS_IMPL_GNUSTEP
973   static float advances[1024];
974   float *adv = advances;
975 #else
976   static CGSize advances[1024];
977   CGSize *adv = advances;
978 #endif
979   struct face *face;
980   NSRect r;
981   struct nsfont_info *font = ns_tmp_font;
982   NSColor *col, *bgCol;
983   unsigned short *t = s->char2b;
984   int i, len;
985   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
986   int end = isComposite ? s->cmp_to : s->nchars;
988   /* Select face based on input flags */
989   switch (ns_tmp_flags)
990     {
991     case NS_DUMPGLYPH_CURSOR:
992       face = s->face;
993       break;
994     case NS_DUMPGLYPH_MOUSEFACE:
995       face = FACE_FROM_ID (s->f,
996                            FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
997       if (!face)
998         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
999       break;
1000     default:
1001       face = s->face;
1002     }
1004   r.origin.x = s->x;
1005   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1006     r.origin.x += abs (s->face->box_line_width);
1008   r.origin.y = s->y;
1009   r.size.height = FONT_HEIGHT (font);
1011   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1012      NS to render the string, it will come out differently from the individual
1013      character widths added up because of layout processing. */
1014   {
1015     XCharStruct *cs;
1016     int cwidth, twidth = 0;
1017     int hi, lo;
1018     /* FIXME: composition: no vertical displacement is considered. */
1019     t += s->cmp_from; /* advance into composition */
1020     for (i = s->cmp_from; i < end; i++, t++)
1021       {
1022         hi = (*t & 0xFF00) >> 8;
1023         lo = *t & 0x00FF;
1024         if (isComposite)
1025           {
1026             if (!s->first_glyph->u.cmp.automatic)
1027                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1028             else
1029               {
1030                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1031                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1032                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1033                     cwidth = LGLYPH_WIDTH (glyph);
1034                 else
1035                   {
1036                     cwidth = LGLYPH_WADJUST (glyph);
1037 #ifdef NS_IMPL_GNUSTEP
1038                     *(adv-1) += LGLYPH_XOFF (glyph);
1039 #else
1040                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1041 #endif
1042                   }
1043               }
1044           }
1045         else
1046           {
1047             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1048               ns_glyph_metrics (font, hi);
1049             cwidth = font->metrics[hi][lo].width;
1050           }
1051         twidth += cwidth;
1052 #ifdef NS_IMPL_GNUSTEP
1053         *adv++ = cwidth;
1054         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1055 #else
1056         (*adv++).width = cwidth;
1057 #endif
1058       }
1059     len = adv - advances;
1060     r.size.width = twidth;
1061     *c = 0;
1062   }
1064   /* fill background if requested */
1065   if (with_background && !isComposite)
1066     {
1067       NSRect br = r;
1068       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1069       int mbox_line_width = max (s->face->box_line_width, 0);
1071       if (s->row->full_width_p)
1072         {
1073           if (br.origin.x <= fibw + 1 + mbox_line_width)
1074             {
1075               br.size.width += br.origin.x - mbox_line_width;
1076               br.origin.x = mbox_line_width;
1077             }
1078           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1079                 <= fibw+1)
1080             br.size.width += fibw;
1081         }
1082       if (s->face->box == FACE_NO_BOX)
1083         {
1084           /* expand unboxed top row over internal border */
1085           if (br.origin.y <= fibw + 1 + mbox_line_width)
1086             {
1087               br.size.height += br.origin.y;
1088               br.origin.y = 0;
1089             }
1090         }
1091       else
1092         {
1093           int correction = abs (s->face->box_line_width)+1;
1094           br.origin.y += correction;
1095           br.size.height -= 2*correction;
1096           br.origin.x += correction;
1097           br.size.width -= 2*correction;
1098         }
1100       if (!s->face->stipple)
1101         [(NS_FACE_BACKGROUND (face) != 0
1102           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1103           : FRAME_BACKGROUND_COLOR (s->f)) set];
1104       else
1105         {
1106           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1107           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1108         }
1109       NSRectFill (br);
1110     }
1113   /* set up for character rendering */
1114   r.origin.y += font->voffset + (s->height - font->height)/2;
1116   col = (NS_FACE_FOREGROUND (face) != 0
1117          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1118          : FRAME_FOREGROUND_COLOR (s->f));
1119   /* FIXME: find another way to pass this */
1120   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1121            : (NS_FACE_BACKGROUND (face) != 0
1122               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1123               : FRAME_BACKGROUND_COLOR (s->f)));
1125   /* render under GNUstep using DPS */
1126 #ifdef NS_IMPL_GNUSTEP
1127   {
1128     NSGraphicsContext *context = GSCurrentContext ();
1130     DPSgsave (context);
1131     [font->nsfont set];
1133     /* do erase if "foreground" mode */
1134     if (bgCol != nil)
1135       {
1136         [bgCol set];
1137         DPSmoveto (context, r.origin.x, r.origin.y);
1138 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1139         DPSxshow (context, cbuf, advances, len);
1140         DPSstroke (context);
1141         [col set];
1142 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1143       }
1145     /* do underline */
1146     if (face->underline_p)
1147       {
1148         if (face->underline_color != 0)
1149           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1150         else
1151           [col set];
1152         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1153         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1154         if (face->underline_color != 0)
1155           [col set];
1156       }
1157     else
1158       [col set];
1160     /* draw with DPSxshow () */
1161     DPSmoveto (context, r.origin.x, r.origin.y);
1162     DPSxshow (context, cbuf, advances, len);
1163     DPSstroke (context);
1165     DPSgrestore (context);
1166     return to-from;
1167   }
1169 #else  /* NS_IMPL_COCOA */
1170   {
1171     CGContextRef gcontext =
1172       [[NSGraphicsContext currentContext] graphicsPort];
1173     static CGAffineTransform fliptf;
1174     static BOOL firstTime = YES;
1176     if (firstTime)
1177       {
1178         firstTime = NO;
1179         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1180       }
1182     CGContextSaveGState (gcontext);
1184     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1186     CGContextSetFont (gcontext, font->cgfont);
1187     CGContextSetFontSize (gcontext, font->size);
1188     if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1189       CGContextSetShouldAntialias (gcontext, 0);
1190     else
1191       CGContextSetShouldAntialias (gcontext, 1);
1192     if (EQ (ns_use_qd_smoothing, Qt))
1193       CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1195     CGContextSetTextMatrix (gcontext, fliptf);
1197     if (bgCol != nil)
1198       {
1199         /* foreground drawing; erase first to avoid overstrike */
1200         [bgCol set];
1201         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1202         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1203         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1204         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1205       }
1207     if (face->underline_p)
1208       {
1209         if (face->underline_color != 0)
1210           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1211         else
1212           [col set];
1213         CGContextBeginPath (gcontext);
1214         CGContextMoveToPoint (gcontext,
1215                               r.origin.x, r.origin.y + font->underpos);
1216         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1217                                 r.origin.y + font->underpos);
1218         CGContextStrokePath (gcontext);
1219         if (face->underline_color != 0)
1220           [col set];
1221       }
1222     else
1223       [col set];
1225     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1226     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1227                                     advances, len);
1229     if (face->overstrike)
1230       {
1231         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1232         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1233                                         advances, len);
1234       }
1236     CGContextRestoreGState (gcontext);
1237     return;
1238   }
1239 #endif  /* NS_IMPL_COCOA */
1245 /* ==========================================================================
1247     Font glyph and metrics caching functions
1249    ========================================================================== */
1251 /* Find and cache corresponding glyph codes for unicode values in given
1252    hi-byte block of 256. */
1253 static void
1254 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1256 #ifdef NS_IMPL_COCOA
1257   static EmacsGlyphStorage *glyphStorage;
1258   static char firstTime = 1;
1259 #endif
1260   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1261   unsigned int i, g, idx;
1262   unsigned short *glyphs;
1264   if (NSFONT_TRACE)
1265     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1266             font_info, block);
1268  BLOCK_INPUT;
1270 #ifdef NS_IMPL_COCOA
1271   if (firstTime)
1272     {
1273       firstTime = 0;
1274       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1275     }
1276 #endif
1278   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1279   if (!unichars || !(font_info->glyphs[block]))
1280     abort ();
1282   /* create a string containing all unicode characters in this block */
1283   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1284     if (idx < 0xD800 || idx > 0xDFFF)
1285       unichars[i] = idx;
1286     else
1287       unichars[i] = 0xFEFF;
1288   unichars[0x100] = 0;
1290   {
1291 #ifdef NS_IMPL_COCOA
1292     NSString *allChars = [[NSString alloc]
1293                                initWithCharactersNoCopy: unichars
1294                                                  length: 0x100
1295                                            freeWhenDone: NO];
1296     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1297     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1298     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1299     unsigned int gInd =0, cInd =0;
1301     [glyphStorage setString: allChars font: font_info->nsfont];
1302     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1303                         desiredNumberOfCharacters: glyphStorage->maxChar
1304                                        glyphIndex: &gInd characterIndex: &cInd];
1305 #endif
1306     glyphs = font_info->glyphs[block];
1307     for (i =0; i<0x100; i++, glyphs++)
1308       {
1309 #ifdef NS_IMPL_GNUSTEP
1310         g = unichars[i];
1311 #else
1312         g = glyphStorage->cglyphs[i];
1313         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1314         if (g > numGlyphs)
1315           g = 0xFFFF; /* hopefully unused... */
1316 #endif
1317         *glyphs = g;
1318       }
1320 #ifdef NS_IMPL_COCOA
1321     [allChars release];
1322 #endif
1323   }
1325   UNBLOCK_INPUT;
1326   xfree (unichars);
1330 /* Determine and cache metrics for corresponding glyph codes in given
1331    hi-byte block of 256. */
1332 static void
1333 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1335   unsigned int i, g;
1336   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1337   NSFont *sfont;
1338   struct font_metrics *metrics;
1340   if (NSFONT_TRACE)
1341     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1342             font_info, block);
1344 #ifdef NS_IMPL_GNUSTEP
1345   /* not implemented yet (as of startup 0.18), so punt */
1346   if (numGlyphs == 0)
1347     numGlyphs = 0x10000;
1348 #endif
1350  BLOCK_INPUT;
1351  sfont = [font_info->nsfont screenFont];
1353   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1354   bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1355   if (!(font_info->metrics[block]))
1356     abort ();
1358   metrics = font_info->metrics[block];
1359   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1360     {
1361       float w, lb, rb;
1362       NSRect r = [sfont boundingRectForGlyph: g];
1364 #ifdef NS_IMPL_GNUSTEP
1365       {
1366         /* lord help us */
1367         NSString *s = [NSString stringWithFormat: @"%c", g];
1368         w = [sfont widthOfString: s];
1369       }
1370 #else
1371       w = [sfont advancementForGlyph: g].width;
1372 #endif
1373       w = max (w, 2.0);
1374       metrics->width = lrint (w);
1376       lb = r.origin.x;
1377       rb = r.size.width - w;
1378       if (lb < 0)
1379         metrics->lbearing = round (lb);
1380       if (font_info->ital)
1381         rb += 0.22 * font_info->height;
1382       metrics->rbearing = lrint (w + rb);
1384       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1385  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1386       metrics->ascent = r.size.height - metrics->descent;
1387 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1388     }
1389   UNBLOCK_INPUT;
1393 #ifdef NS_IMPL_COCOA
1394 /* helper for font glyph setup */
1395 @implementation EmacsGlyphStorage
1397 - init
1399   return [self initWithCapacity: 1024];
1402 - initWithCapacity: (unsigned long) c
1404   self = [super init];
1405   maxChar = 0;
1406   maxGlyph = 0;
1407   dict = [NSMutableDictionary new];
1408   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1409   return self;
1412 - (void) dealloc
1414   if (attrStr != nil)
1415     [attrStr release];
1416   [dict release];
1417   xfree (cglyphs);
1418   [super dealloc];
1421 - (void) setString: (NSString *)str font: (NSFont *)font
1423   [dict setObject: font forKey: NSFontAttributeName];
1424   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1425   maxChar = [str length];
1426   maxGlyph = 0;
1429 /* NSGlyphStorage protocol */
1430 - (unsigned int)layoutOptions
1432   return 0;
1435 - (NSAttributedString *)attributedString
1437   return attrStr;
1440 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1441         forStartingGlyphAtIndex: (unsigned int)glyphIndex
1442         characterIndex: (unsigned int)charIndex
1444   len = glyphIndex+length;
1445   for (i =glyphIndex; i<len; i++)
1446     cglyphs[i] = glyphs[i-glyphIndex];
1447   if (len > maxGlyph)
1448     maxGlyph = len;
1451 - (void)setIntAttribute: (int)attributeTag value: (int)val
1452         forGlyphAtIndex: (unsigned)glyphIndex
1454   return;
1457 @end
1458 #endif /* NS_IMPL_COCOA */
1461 /* Debugging */
1462 void
1463 ns_dump_glyphstring (struct glyph_string *s)
1465   int i;
1467   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1468 "overlap = %d, bg_filled = %d:",
1469            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1470            s->row->overlapping_p, s->background_filled_p);
1471   for (i =0; i<s->nchars; i++)
1472     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1473   fprintf (stderr, "\n");
1477 void
1478 syms_of_nsfont ()
1480   nsfont_driver.type = Qns;
1481   register_font_driver (&nsfont_driver, NULL);
1482   DEFSYM (Qapple, "apple");
1483   DEFSYM (Qroman, "roman");
1484   DEFSYM (Qmedium, "medium");
1487 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae