(confirm-nonexistent-file-or-buffer):
[emacs.git] / src / nsfont.m
blob7adced73c129cacd073e4f2d66db282f6db72b74
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006, 2007, 2008 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 #include "config.h"
25 #include "lisp.h"
26 #include "dispextern.h"
27 #include "composite.h"
28 #include "blockinput.h"
29 #include "charset.h"
30 #include "frame.h"
31 #include "window.h"
32 #include "fontset.h"
33 #include "nsterm.h"
34 #include "frame.h"
35 #include "character.h"
36 #include "font.h"
38 #define NSFONT_TRACE 0
40 extern Lisp_Object Qns;
41 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
42 static Lisp_Object Qapple, Qroman, Qmedium;
43 extern Lisp_Object ns_expand_space;
44 extern Lisp_Object Qappend;
45 extern int ns_antialias_text, ns_use_qd_smoothing;
46 extern float ns_antialias_threshold;
47 extern int ns_tmp_flags;
48 extern struct nsfont_info *ns_tmp_font;
50 /* font glyph and metrics caching functions, implemented at end */
51 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
52                               unsigned char block);
53 static void ns_glyph_metrics (struct nsfont_info *font_info,
54                               unsigned char block);
57 /* ==========================================================================
59     Utilities
61    ========================================================================== */
64 /* Replace spaces w/another character so emacs core font parsing routines
65    aren't thrown off. */
66 static void
67 nsfont_escape_name (char *name)
69   int i =0, len =strlen (name);
70   for ( ; i<len; i++)
71     if (name[i] == ' ')
72       name[i] = '_';
76 /* Reconstruct spaces in a font family name passed through emacs. */
77 static void
78 nsfont_unescape_name (char *name)
80   int i =0, len =strlen (name);
81   for ( ; i<len; i++)
82     if (name[i] == '_')
83       name[i] = ' ';
87 /* Extract family name from a font spec. */
88 static NSString *
89 nsfont_get_family (Lisp_Object font_spec)
91   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
92   if (NILP (tem))
93       return nil;
94   else
95     {
96       char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
97       NSString *family;
98       nsfont_unescape_name (tmp);
99       /* TODO: this seems to be needed only for font names that are
100                hard-coded into emacs, like 'helvetica' for splash screen */
101       if (tmp)
102         tmp[0] = toupper (tmp[0]);
103       family = [NSString stringWithUTF8String: tmp];
104       free (tmp);
105       return family;
106     }
110 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
111 /* TODO (20080601): The font backend's strategy for handling font
112            styles continues to evolve.  When/if this stabilizes, we
113            can change the code here to be more sophisticated and accurate.
114            For now, we rely on "normal/plain" style being numeric 100. */
115 #define STYLE_REF 100
116 static unsigned int
117 nsfont_spec_to_traits (Lisp_Object font_spec)
119   unsigned int traits = 0;
120   int n;
122   n = FONT_WEIGHT_NUMERIC (font_spec);
123   if (n != -1)
124       traits |= (n > STYLE_REF) ? NSBoldFontMask
125                                 : (n < STYLE_REF) ? NSUnboldFontMask : 0;
127   n = FONT_SLANT_NUMERIC (font_spec);
128   if (n != -1)
129       traits |= (n > STYLE_REF) ? NSItalicFontMask
130                                 : (n < STYLE_REF) ? NSUnitalicFontMask : 0;
132   n = FONT_WIDTH_NUMERIC (font_spec);
133   if (n > -1)
134       traits |= (n > STYLE_REF + 10) ? NSExpandedFontMask
135                                 : (n < STYLE_REF - 10) ? NSExpandedFontMask : 0;
137 /*fprintf (stderr, "  returning traits = %u\n", traits); */
138   return traits;
142 /* Converts NSArray of PS name, non-family part, weight, and traits to a
143    font backend font-entity. */
144 static Lisp_Object
145 nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
147   Lisp_Object font_entity = font_make_entity ();
148   unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
149 /*   NSString *psName = [famMember objectAtIndex: 0]; */
150   NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
151   char *escapedFamily = strdup ([family UTF8String]);
153   nsfont_escape_name (escapedFamily);
154   [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
155                                range: NSMakeRange (0, [suffix length])];
157   ASET (font_entity, FONT_TYPE_INDEX, Qns);
158   ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
159   ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
160   ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
161   ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
163   FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
164       traits & NSBoldFontMask ? Qbold : Qmedium);
165   FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
166       traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
167   FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
168       traits & NSCondensedFontMask ? Qcondensed :
169         traits & NSExpandedFontMask ? Qexpanded : Qnormal);
171   ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
172   ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
173   ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
175   if (NSFONT_TRACE)
176     {
177       fprintf (stderr, "created font_entity:\n    ");
178       debug_print (font_entity);
179     }
181   [suffix release];
182   free (escapedFamily);
183   return font_entity;
187 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
188 static int
189 nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
191   int i, d = 0;
192   for (i = 0; i < sizeof (unsigned int) * 8; i++)
193     {
194       d += (traits1 & 0x1) ^ (traits2 & 0x1);
195       traits1 >>= 1;
196       traits2 >>= 1;
197     }
198   return d;
202 /* Default font entity based on Monaco. */
203 static Lisp_Object
204 nsfont_fallback_entity ()
206   NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
207   NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
208                                     [NSNumber numberWithUnsignedInt: 5],
209                                     [NSNumber numberWithUnsignedInt: 0], nil];
210   return nsfont_fmember_to_entity (family, famMemberSpec);
214 /* ==========================================================================
216     Font driver implementation
218    ========================================================================== */
220 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
221 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
222 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
223 static Lisp_Object nsfont_list_family (Lisp_Object frame);
224 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
225                                  int pixel_size);
226 static void nsfont_close (FRAME_PTR f, struct font *font);
227 static int nsfont_has_char (Lisp_Object entity, int c);
228 static unsigned int nsfont_encode_char (struct font *font, int c);
229 static int nsfont_text_extents (struct font *font, unsigned int *code,
230                                 int nglyphs, struct font_metrics *metrics);
231 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
232                         int with_background);
234 struct font_driver nsfont_driver =
235   {
236     0,                          /* Qns */
237     1,                          /* case sensitive */
238     nsfont_get_cache,
239     nsfont_list,
240     nsfont_match,
241     nsfont_list_family,
242     NULL,                       /*free_entity */
243     nsfont_open,
244     nsfont_close,
245     NULL,                       /* prepare_face */
246     NULL,                       /* done_face */
247     nsfont_has_char,
248     nsfont_encode_char,
249     nsfont_text_extents,
250     nsfont_draw,
251     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
252                  anchor_point, otf_capability, otf_driver,
253                  start_for_frame, end_for_frame, shape */
254   };
257 /* Return a cache of font-entities on FRAME.  The cache must be a
258    cons whose cdr part is the actual cache area.  */
259 static Lisp_Object
260 nsfont_get_cache (FRAME_PTR frame)
262   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
263   return (dpyinfo->name_list_element);
267 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value
268    is a **list** of font-entities.  This is the sole API that
269    allocates font-entities.  */
270 static Lisp_Object
271 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
273   Lisp_Object list = Qnil;
274   Lisp_Object tem;
275   NSString *family;
276   NSArray *families;
277   NSEnumerator *famEnum;
278   NSFontManager *fontMgr;
279   unsigned int traits = nsfont_spec_to_traits (font_spec);
281   if (NSFONT_TRACE)
282     {
283       fprintf (stderr, "nsfont: list for fontspec:\n    ");
284       debug_print (font_spec);
285     }
287   /* if has non-unicode registry, give up */
288   tem = AREF (font_spec, FONT_REGISTRY_INDEX);
289   if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
290     return Qnil;
292   fontMgr = [NSFontManager sharedFontManager];
294   family = nsfont_get_family (font_spec);
296   if (family != nil)
297     families = [NSArray arrayWithObject: family];
298   else
299     families = [fontMgr availableFontFamilies];
301   for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
302     {
303       NSEnumerator *fm;
304       NSArray *fmember, *firstMember = nil;
305       unsigned int mtraits;
306       BOOL foundItal = NO || (traits & NSUnitalicFontMask);
307       NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
308 #ifdef NS_IMPL_COCOA
309       /* LastResort is special: not a family but a font name only */
310       if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
311         {
312           famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
313               @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
314               [NSNumber numberWithUnsignedInt: 0], nil]];
315         }
316 #endif
318       /* fmember = [postscriptName style weight traits] */
319       fm  = [famMembers objectEnumerator];
320       while (fmember = [fm nextObject])
321         {
322           mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
323           if ((mtraits & traits) == traits)
324             {
325               list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
326               if (mtraits & NSItalicFontMask)
327                 foundItal = YES;
328               if (firstMember == nil)
329                 firstMember = fmember;
330             }
331         }
332       if (foundItal == NO && firstMember != nil)
333         {
334           /* no italic member found; add a synthesized one */
335           NSMutableArray *smember = [firstMember mutableCopy];
336           [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
337           mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
338           mtraits |= NSItalicFontMask;
339           [smember replaceObjectAtIndex: 3
340                    withObject: [NSNumber numberWithUnsignedInt: mtraits]];
341 /*NSLog (@"-- adding synthItal member: %@", smember); */
342           list = Fcons (nsfont_fmember_to_entity (family, smember), list);
343           [smember release];
344         }
345     }
347   if (NSFONT_TRACE)
348       fprintf (stderr, "    Returning %d entities.\n", XINT (Flength (list)));
350   return list;
354 /* Return a font entity most closely maching with FONT_SPEC on
355    FRAME.  The closeness is determined by the font backend, thus
356    `face-font-selection-order' is ignored here.  */
357 static Lisp_Object
358 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
360   long traits = nsfont_spec_to_traits (font_spec);
361   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
362   NSString *family;
363   Lisp_Object tem;
365   if (NSFONT_TRACE)
366     {
367       fprintf (stderr, "nsfont: match for fontspec:\n    ");
368       debug_print (font_spec);
369     }
371   /* if has non-unicode registry, just return fallback */
372 #if 0
373   tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
374   if (!NILP (tem))
375     fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
376 #endif
377   tem = AREF (font_spec, FONT_REGISTRY_INDEX);
378   if (!NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
379     return nsfont_fallback_entity ();
381   family = nsfont_get_family (font_spec);
383   if (family != nil)
384     {
385       /* try to find close font in family */
386       NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
387       NSEnumerator *fm = [famMembers objectEnumerator];
388       NSArray *fmember;
389       int minDist = sizeof (unsigned int) * 8 + 1;
390       int bestMatchIdx = -1;
391       int i;
393       for (i =0; fmember = [fm nextObject]; i++)
394         {
395           unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
396           int dist = nsfont_trait_distance ((mtraits & traits), traits);
397           if (dist < minDist)
398             {
399               bestMatchIdx = i;
400               minDist = dist;
401             }
402         }
403       if (bestMatchIdx != -1)
404         return nsfont_fmember_to_entity
405           (family, [famMembers objectAtIndex: bestMatchIdx]);
406     }
408   /* no family that had members was given; find any font matching traits */
409   {
410     NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
411     if (fontNames && [fontNames count]  > 0)
412       {
413         NSString *fontName = [fontNames objectAtIndex: 0];
414         /* XXX: is there a more efficient way to get family name? */
415         NSFont *font = [NSFont fontWithName: fontName size: 0];
416         if (font != nil)
417           {
418             /* now need to get suffix part of name.. */
419             NSString *family = [font familyName];
420             NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
421                                  objectEnumerator];
422             NSArray *fmember;
423             while (fmember = [fm nextObject])
424               {
425                 unsigned int mtraits =
426                   [[fmember objectAtIndex: 3] unsignedIntValue];
427                 if (mtraits & traits == traits)
428                   return nsfont_fmember_to_entity (family, fmember);
429               }
430           }
431       }
432   }
434   /* if we get here, return the fallback */
435   if (NSFONT_TRACE)
436       fprintf (stderr, "    *** returning fallback\n");
438   return nsfont_fallback_entity ();
442 /* List available families.  The value is a list of family names
443    (symbols). */
444 static Lisp_Object
445 nsfont_list_family (Lisp_Object frame)
447   Lisp_Object list = Qnil;
448   NSEnumerator *families =
449     [[[NSFontManager sharedFontManager] availableFontFamilies]
450       objectEnumerator];
451   NSString *family;
452   while (family = [families nextObject])
453       list = Fcons (intern ([family UTF8String]), list);
454   /* FIXME: escape the name? */
456   if (NSFONT_TRACE)
457     fprintf (stderr, "nsfont: list families returning %d entries\n",
458             XINT (Flength (list)));
460   return list;
464 /* utility: get width of a char c in screen font sfont */
465 static float
466 nsfont_char_width (NSFont *sfont, int c)
468   float w;
469   NSString *cstr = [NSString stringWithFormat: @"%c", c];
470 #ifdef NS_IMPL_COCOA
471   NSGlyph glyph = [sfont glyphWithName: cstr];
472   if (glyph)
473     {
474       float w = [sfont advancementForGlyph: glyph].width;
475       if (w >= 1.5)
476         return w;
477     }
478 #endif
479   w = [sfont widthOfString: cstr];
480   return max (w, 2.0);
484 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
485    scalable, open it with PIXEL_SIZE.  */
486 static Lisp_Object
487 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
489   BOOL synthItal;
490   struct nsfont_info *font_info;
491   struct font *font;
492   unsigned int traits = nsfont_spec_to_traits (font_entity);
493   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
494   NSString *family;
495   NSFont *nsfont, *sfont;
496   Lisp_Object tem;
497   NSRect brect;
498   Lisp_Object font_object;
499   int i;
500   int fixLeopardBug;
501   static NSMutableDictionary *fontCache = nil;
502   NSNumber *cached;
504   /* 2008/03/08: The same font may end up being requested for different
505      entities, due to small differences in numeric values or other issues,
506      or for different copies of the same entity.  Therefore we cache to
507      avoid creating multiple struct font objects (with metrics cache, etc.)
508      for the same NSFont object.
509      2008/06/01: This is still an issue after font backend refactoring. */
510   if (fontCache == nil)
511     fontCache = [[NSMutableDictionary alloc] init];
513   if (NSFONT_TRACE)
514     {
515       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
516       debug_print (font_entity);
517     }
519   if (pixel_size <= 0)
520     {
521       /* try to get it out of frame params */
522         Lisp_Object tem = get_frame_param (f, Qfontsize);
523         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
524     }
526   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
527   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
528                                        9);
529   family = nsfont_get_family (font_entity);
530   if (NSFONT_TRACE)
531     {
532       fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\titalic = %d\n",
533                [family UTF8String], traits, traits & NSBoldFontMask,
534                traits & NSItalicFontMask);
535     }
537   /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
538   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
539   nsfont = [fontMgr fontWithFamily: family
540                             traits: traits weight: fixLeopardBug
541                               size: pixel_size];
542   /* if didn't find, try synthetic italic */
543   if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
544     {
545       nsfont = [fontMgr fontWithFamily: family
546                                 traits: traits & ~NSItalicFontMask
547                                 weight: fixLeopardBug size: pixel_size];
548     }
549 #ifdef NS_IMPL_COCOA
550   /* LastResort not really a family */
551   if (nsfont == nil && [@"LastResort" isEqualToString: family])
552     {
553       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
554     }
555 #endif
557   if (nsfont == nil)
558     {
559       message_with_string ("*** Warning: font in family '%s' not found",
560                           build_string ([family UTF8String]), 1);
561       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
562       if (!nsfont)
563         {
564           fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
565           return Qnil;
566         }
567     }
569   if (NSFONT_TRACE)
570     NSLog (@"%@\n", nsfont);
572   /* Check the cache */
573   cached = [fontCache objectForKey: nsfont];
574   if (cached != nil && !synthItal)
575     {
576       if (NSFONT_TRACE)
577         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
578       return (Lisp_Object)[cached unsignedLongValue];
579     }
580   else
581     {
582       font_object = font_make_object (VECSIZE (struct nsfont_info),
583                                       font_entity, pixel_size);
584       if (!synthItal)
585         [fontCache
586           setObject: [NSNumber numberWithUnsignedLong:
587                                  (unsigned long)font_object]
588           forKey: nsfont];
589     }
591   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
592   font = (struct font *)font_info;
593   if (!font)
594     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
596   font_info->glyphs = (unsigned short **)
597     xmalloc (0x100 * sizeof (unsigned short *));
598   font_info->metrics = (struct font_metrics **)
599     xmalloc (0x100 * sizeof (struct font_metrics *));
600   if (!font_info->glyphs || !font_info->metrics)
601     return Qnil;
602   bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
603   bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
605   BLOCK_INPUT;
607   /* for metrics */
608   sfont = [nsfont screenFont];
609   if (sfont == nil)
610     sfont = nsfont;
612   /* non-metric backend font struct fields */
613   font = (struct font *) font_info;
614   font->pixel_size = [sfont pointSize];
615   font->driver = &nsfont_driver;
616   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
617   font->encoding_charset = -1;
618   font->repertory_charset = -1;
619   font->default_ascent = 0;
620   font->vertical_centering = 0;
621   font->baseline_offset = 0;
622   font->relative_compose = 0;
623   font->font_encoder = NULL;
625   /* TODO: does anything care about this? */
626   font->props[FONT_FORMAT_INDEX] = Qns;
627   font->props[FONT_FILE_INDEX] = Qnil;
629   {
630     double expand, shrink, hshrink;
631     float full_height, min_height, hd;
632     const char *fontName = [[nsfont fontName] UTF8String];
633     int len = strlen (fontName);
635 #ifdef NS_IMPL_GNUSTEP
636     font_info->nsfont = sfont;
637 #else
638     font_info->nsfont = nsfont;
639 #endif
640     [font_info->nsfont retain];
642     /* set up ns_font (defined in nsgui.h) */
643     font_info->name = (char *)xmalloc (strlen (fontName)+1);
644     bcopy (fontName, font_info->name, strlen (fontName)+1);
645     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
646     font_info->ital =
647       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
649     /* Metrics etc.; some fonts return an unusually large max advance, so we
650        only use it for fonts that have wide characters. */
651     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
652       [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
654     brect =  [sfont boundingRectForFont];
655     full_height = brect.size.height;
656     min_height = [sfont ascender] - [sfont descender];
657     hd = full_height - min_height;
659     if (!NUMBERP (ns_expand_space))
660       error ("No expand space defined");
662     /* ns_expand_space = 0.0 is use standard height; less shrink, more expand */
663     expand = XFLOATINT (ns_expand_space) + 0.5;
665     if (expand < 0.0)
666       {
667         shrink = 1 + expand;
668         hshrink = 1 + expand / 2.0;
669         expand = 0.0;
670       }
671     else
672       shrink = hshrink = 1.0;
674     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
675     font_info->underwidth = [sfont underlineThickness];
676     font_info->size = font->pixel_size;
677     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
679     /* max bounds */
680     font_info->max_bounds.ascent =
681       lrint (hshrink * [sfont ascender] + expand * hd/2);
682     font_info->max_bounds.descent =
683       -lrint (hshrink* [sfont descender] - expand*hd/2);
684     font_info->height =
685       font_info->max_bounds.ascent + font_info->max_bounds.descent;
686     font_info->max_bounds.width = lrint (font_info->width);
687     font_info->max_bounds.lbearing = lrint (brect.origin.x);
688     font_info->max_bounds.rbearing =
689       lrint (brect.size.width - font_info->width);
690       /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
692 #ifdef NS_IMPL_COCOA
693     /* set up synthItal and the CG font */
694     font_info->synthItal = synthItal;
695     {
696       ATSFontRef atsFont = ATSFontFindFromPostScriptName
697         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
699       if (atsFont == kATSFontRefUnspecified)
700         {
701           /* see if we can get it by dropping italic (then synthesizing) */
702           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
703               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
704                 fontName], kATSOptionFlagsDefault);
705           if (atsFont != kATSFontRefUnspecified)
706               font_info->synthItal = YES;
707           else
708             {
709               /* last resort fallback */
710               atsFont = ATSFontFindFromPostScriptName
711                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
712             }
713         }
714       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
715     }
716 #endif
718     /* set up metrics portion of font struct */
719     font->ascent = [sfont ascender];
720     font->descent = -[sfont descender];
721     font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
722     font->space_width = lrint (nsfont_char_width (sfont, ' '));
723     font->average_width = lrint (font_info->width);
724     font->max_width = lrint (font_info->max_bounds.width);
725     font->height = lrint (font_info->height);
726     font->underline_position = lrint (font_info->underpos);
727     font->underline_thickness = lrint (font_info->underwidth);
729     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
730     font->props[FONT_FULLNAME_INDEX] =
731       make_unibyte_string (font_info->name, strlen (font_info->name));
732   }
733   UNBLOCK_INPUT;
735   return font_object;
739 /* Close FONT on frame F. */
740 static void
741 nsfont_close (FRAME_PTR f, struct font *font)
743   struct nsfont_info *font_info = (struct nsfont_info *)font;
744   int i;
746   /* FIXME: this occurs apparently due to same failure to detect same font
747             that causes need for cache in nsfont_open ()
748             (came after unicode-2 -> trunk) */
749   if (!font_info)
750       return;
752   for (i =0; i<0x100; i++)
753     {
754       if (font_info->glyphs[i])
755         xfree (font_info->glyphs[i]);
756       if (font_info->metrics[i])
757         xfree (font_info->metrics[i]);
758     }
759   [font_info->nsfont release];
760 #ifdef NS_IMPL_COCOA
761       CGFontRelease (font_info->cgfont);
762 #endif
763       xfree (font_info->name);
764       xfree (font_info);
768 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
769    return 1.  If not, return 0.  If a font must be opened to check
770    it, return -1. */
771 static int
772 nsfont_has_char (Lisp_Object entity, int c)
774   return -1;
778 /* Return a glyph code of FONT for character C (Unicode code point).
779    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
780 static unsigned int
781 nsfont_encode_char (struct font *font, int c)
783   struct nsfont_info *font_info = (struct nsfont_info *)font;
784   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
785   unsigned short g;
787   if (c > 0xFFFF)
788     return FONT_INVALID_CODE;
790   /* did we already cache this block? */
791   if (!font_info->glyphs[high])
792     ns_uni_to_glyphs (font_info, high);
794   g = font_info->glyphs[high][low];
795 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
796   return g == 0xFFFF ? FONT_INVALID_CODE : g;
800 /* Perform the size computation of glyphs of FONT and fill in members
801    of METRICS.  The glyphs are specified by their glyph codes in
802    CODE (length NGLYPHS). */
803 static int
804 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
805                      struct font_metrics *metrics)
807   struct nsfont_info *font_info = (struct nsfont_info *)font;
808   struct font_metrics *pcm;
809   unsigned char high, low;
810   int totalWidth = 0;
811   int i;
813   bzero (metrics, sizeof (struct font_metrics));
815   for (i =0; i<nglyphs; i++)
816     {
817       /* get metrics for this glyph, filling cache if need be */
818       /* TODO: get metrics for whole string from an NSLayoutManager
819                (if not too slow) */
820       high = (code[i] & 0xFF00) >> 8;
821       low = code[i] & 0x00FF;
822       if (!font_info->metrics[high])
823         ns_glyph_metrics (font_info, high);
824       pcm = &(font_info->metrics[high][low]);
826       if (metrics->lbearing > totalWidth + pcm->lbearing)
827         metrics->lbearing = totalWidth + pcm->lbearing;
828       if (metrics->rbearing < totalWidth + pcm->rbearing)
829         metrics->rbearing = totalWidth + pcm->rbearing;
830       if (metrics->ascent < pcm->ascent)
831         metrics->ascent = pcm->ascent;
832       if (metrics->descent < pcm->descent)
833         metrics->descent = pcm->descent;
835       totalWidth += pcm->width;
836     }
838   metrics->width = totalWidth;
840   return totalWidth; /* not specified in doc, but xfont.c does it */
844 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
845    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
846    is nonzero, fill the background in advance.  It is assured that
847    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
848 static int
849 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
850              int with_background)
851 /* NOTE: focus and clip must be set
852      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
854   static char cbuf[1024];
855   char *c = cbuf;
856 #ifdef NS_IMPL_GNUSTEP
857   static float advances[1024];
858   float *adv = advances;
859 #else
860   static CGSize advances[1024];
861   CGSize *adv = advances;
862 #endif
863   struct face *face;
864   NSRect r;
865   struct nsfont_info *font = ns_tmp_font;
866   NSColor *col, *bgCol;
867   unsigned short *t = s->char2b;
868   int i, len;
870   /* Select face based on input flags */
871   switch (ns_tmp_flags)
872     {
873     case NS_DUMPGLYPH_CURSOR:
874       face = s->face;
875       break;
876     case NS_DUMPGLYPH_MOUSEFACE:
877       face = FACE_FROM_ID (s->f,
878                            FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
879       if (!face)
880         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
881       break;
882     default:
883       face = s->face;
884     }
886   r.origin.x = s->x;
887   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
888     r.origin.x += abs (s->face->box_line_width);
890   r.origin.y = s->y;
891   r.size.height = FONT_HEIGHT (font);
893   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
894      NS to render the string, it will come out differently from the individual
895      character widths added up because of layout processing. */
896   {
897     XCharStruct *cs;
898     int cwidth, twidth = 0;
899     int hi, lo;
900     char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
901     /* FIXME: composition: no vertical displacement is considered. */
902     t += s->cmp_from; /* advance into composition */
903     for (i = s->cmp_from; i < s->nchars; i++, t++)
904       {
905         hi = (*t & 0xFF00) >> 8;
906         lo = *t & 0x00FF;
907         if (isComposite)
908           {
909             cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
910           }
911         else
912           {
913             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
914               ns_glyph_metrics (font, hi);
915             cwidth = font->metrics[hi][lo].width;
916           }
917         twidth += cwidth;
918 #ifdef NS_IMPL_GNUSTEP
919         *adv++ = cwidth;
920         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
921 #else
922         (*adv++).width = cwidth;
923 #endif
924       }
925     len = adv - advances;
926     r.size.width = twidth;
927     *c = 0;
928   }
930   /* fill background if requested */
931   if (with_background)
932     {
933       NSRect br = r;
934       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
935       int mbox_line_width = max (s->face->box_line_width, 0);
937       if (s->row->full_width_p)
938         {
939           if (br.origin.x <= fibw + 1 + mbox_line_width)
940             {
941               br.size.width += br.origin.x - mbox_line_width;
942               br.origin.x = mbox_line_width;
943             }
944           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
945                 <= fibw+1)
946             br.size.width += fibw;
947         }
948       if (s->face->box == FACE_NO_BOX)
949         {
950           /* expand unboxed top row over internal border */
951           if (br.origin.y <= fibw + 1 + mbox_line_width)
952             {
953               br.size.height += br.origin.y;
954               br.origin.y = 0;
955             }
956         }
957       else
958         {
959           int correction = abs (s->face->box_line_width)+1;
960           br.origin.y += correction;
961           br.size.height -= 2*correction;
962           br.origin.x += correction;
963           br.size.width -= 2*correction;
964         }
966       if (!s->face->stipple)
967         [(NS_FACE_BACKGROUND (face) != 0
968           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
969           : FRAME_BACKGROUND_COLOR (s->f)) set];
970       else
971         {
972           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
973           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
974         }
975       NSRectFill (br);
976     }
979   /* set up for character rendering */
980   r.origin.y += font->voffset + (s->height - font->height)/2;
982   col = (NS_FACE_FOREGROUND (face) != 0
983          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
984          : FRAME_FOREGROUND_COLOR (s->f));
985   /* FIXME: find another way to pass this */
986   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
987            : (NS_FACE_BACKGROUND (face) != 0
988               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
989               : FRAME_BACKGROUND_COLOR (s->f)));
991   /* render under GNUstep using DPS */
992 #ifdef NS_IMPL_GNUSTEP
993   {
994     NSGraphicsContext *context = GSCurrentContext ();
996     DPSgsave (context);
997     [font->nsfont set];
999     /* do erase if "foreground" mode */
1000     if (bgCol != nil)
1001       {
1002         [bgCol set];
1003         DPSmoveto (context, r.origin.x, r.origin.y);
1004 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1005         DPSxshow (context, cbuf, advances, len);
1006         DPSstroke (context);
1007         [col set];
1008 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1009       }
1011     /* do underline */
1012     if (face->underline_p)
1013       {
1014         if (face->underline_color != 0)
1015           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1016         else
1017           [col set];
1018         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1019         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1020         if (face->underline_color != 0)
1021           [col set];
1022       }
1023     else
1024       [col set];
1026     /* draw with DPSxshow () */
1027     DPSmoveto (context, r.origin.x, r.origin.y);
1028     DPSxshow (context, cbuf, advances, len);
1029     DPSstroke (context);
1031     DPSgrestore (context);
1032     return to-from;
1033   }
1035 #else  /* NS_IMPL_COCOA */
1036   {
1037     CGContextRef gcontext =
1038       [[NSGraphicsContext currentContext] graphicsPort];
1039     static CGAffineTransform fliptf;
1040     static BOOL firstTime = YES;
1042     if (firstTime)
1043       {
1044         firstTime = NO;
1045         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1046       }
1048     CGContextSaveGState (gcontext);
1050     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1052     CGContextSetFont (gcontext, font->cgfont);
1053     CGContextSetFontSize (gcontext, font->size);
1054     if (ns_antialias_text == NO || font->size <= ns_antialias_threshold)
1055       CGContextSetShouldAntialias (gcontext, 0);
1056     else
1057       CGContextSetShouldAntialias (gcontext, 1);
1058     if (EQ (ns_use_qd_smoothing, Qt))
1059       CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1061     CGContextSetTextMatrix (gcontext, fliptf);
1063     if (bgCol != nil)
1064       {
1065         /* foreground drawing; erase first to avoid overstrike */
1066         [bgCol set];
1067         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1068         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1069         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1070         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1071       }
1073     if (face->underline_p)
1074       {
1075         if (face->underline_color != 0)
1076           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1077         else
1078           [col set];
1079         CGContextBeginPath (gcontext);
1080         CGContextMoveToPoint (gcontext,
1081                               r.origin.x, r.origin.y + font->underpos);
1082         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1083                                 r.origin.y + font->underpos);
1084         CGContextStrokePath (gcontext);
1085         if (face->underline_color != 0)
1086           [col set];
1087       }
1088     else
1089       [col set];
1091     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1092     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1093                                     advances, len);
1095     if (face->overstrike)
1096       {
1097         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1098         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1099                                         advances, len);
1100       }
1102     CGContextRestoreGState (gcontext);
1103     return;
1104   }
1105 #endif  /* NS_IMPL_COCOA */
1110 /*  Auto-creates a fontset built around the font in font_object,
1111     by creating an attributed string with characters from each
1112     script, then requesting the NS text system to fix attributes
1113     in range. */
1114 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1116   Lisp_Object script, famAndReg;
1117   struct nsfont_info *font_info =
1118     (struct nsfont_info *)XFONT_OBJECT (font_object);
1120   /* NS text system (and char buf) init */
1121   static NSTextStorage *store;
1122   static NSLayoutManager *layout;
1123   static NSRange range;
1124   static NSMutableDictionary *attribs;
1125   static Lisp_Object *scripts;
1126   static int nscripts;
1127   static int *scriptsNchars;
1128   static BOOL firstTime = YES;
1129   Lisp_Object regString = build_string ("iso10646-1");
1130   int i, j;
1132   if (firstTime == YES)
1133     {
1134       nscripts = XINT (Flength (Vscript_representative_chars));
1135       scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1136       unsigned char *buf = malloc (4*nscripts*sizeof (char));
1137       Lisp_Object scriptsChars = Vscript_representative_chars;
1138       unsigned char *tpos = buf;
1140       scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1142       for (i =0; i<nscripts; i++)
1143         {
1144           Lisp_Object sChars = XCAR (scriptsChars);
1145           Lisp_Object chars = XCDR (sChars);
1146           unsigned int ch, c =0;
1147           scripts[i] = XCAR (sChars);
1149           while (CONSP (chars))
1150             {
1151               ch = XUINT (XCAR (chars));
1152               chars = XCDR (chars);
1153               CHAR_STRING_ADVANCE (ch, tpos);
1154               c++;
1155             }
1156           scriptsNchars[i] = c;
1158           scriptsChars = XCDR (scriptsChars);
1159         }
1160       *tpos = '\0';
1162       store = [[NSTextStorage alloc] init];
1163       layout = [[NSLayoutManager alloc] init];
1164       [store addLayoutManager: layout];
1165       [layout release];
1167       [store beginEditing];
1168       [[store mutableString] appendString:
1169                                [NSString stringWithUTF8String: buf]];
1170       [store endEditing];
1172       free (buf);
1173       range = NSMakeRange (0, [store length]);
1175       attribs = [[NSMutableDictionary alloc] init];
1176       firstTime = NO;
1177     }
1179   /* set the fonts */
1180   [store beginEditing];
1181   [store removeAttribute: NSFontAttributeName range: range];
1182   [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1183   [store addAttributes: attribs range: range];
1184   [store endEditing];
1186   /* read them out */
1187   {
1188     NSMutableDictionary *map =
1189       [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1190     NSEnumerator *fonts;
1191     NSFont *cfont = nil, *tfont;
1192     NSNumber *n;
1193     int idx = 0;
1194     int max;
1195     for (i =0; i<nscripts; i++)
1196       {
1197         [map removeAllObjects];
1198         for (j =0; j<scriptsNchars[i]; j++)
1199           {
1200             cfont = [store attribute: NSFontAttributeName atIndex: idx++
1201                       effectiveRange: NULL];
1202             n = [map objectForKey: cfont];
1203             if (n == nil)
1204               n = [NSNumber numberWithInt: 1];
1205             else
1206               n = [NSNumber numberWithInt: [n intValue] + 1];
1207             [map setObject: n forKey: cfont];
1208           }
1210         /* majority rules */
1211         max = 0;
1212         fonts = [map keyEnumerator];
1213         while (tfont = [fonts nextObject])
1214           {
1215             n = [map objectForKey: tfont];
1216             if ([n intValue] > max)
1217               {
1218                 cfont = tfont;
1219                 max = [n intValue];
1220               }
1221           }
1223         if (cfont != nil)
1224           {
1225             char *family = strdup([[cfont familyName] UTF8String]);
1226             Lisp_Object famAndReg;
1228             nsfont_escape_name (family);
1229             famAndReg = Fcons (build_string (family), regString);
1231             if (NSFONT_TRACE)
1232               fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1233                       font_info->name, family,
1234                        SDATA (SYMBOL_NAME (scripts[i])));
1236             Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1237             free (family);
1238           }
1239         else
1240           {
1241             fprintf (stderr, "%s fontset: none found for script '%s'\n",
1242                     font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1243          }
1244       }  /* for i = script */
1245   }
1250 /* ==========================================================================
1252     Font glyph and metrics caching functions
1254    ========================================================================== */
1256 /* Find and cache corresponding glyph codes for unicode values in given
1257    hi-byte block of 256. */
1258 static void
1259 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1261 #ifdef NS_IMPL_COCOA
1262   static EmacsGlyphStorage *glyphStorage;
1263   static char firstTime = 1;
1264 #endif
1265   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1266   unsigned int i, g, idx;
1267   unsigned short *glyphs;
1269   if (NSFONT_TRACE)
1270     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1271             font_info, block);
1273  BLOCK_INPUT;
1275 #ifdef NS_IMPL_COCOA
1276   if (firstTime)
1277     {
1278       firstTime = 0;
1279       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1280     }
1281 #endif
1283   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1284   if (!unichars || !(font_info->glyphs[block]))
1285     abort ();
1287   /* create a string containing all unicode characters in this block */
1288   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1289     if (idx < 0xD800 || idx > 0xDFFF)
1290       unichars[i] = idx;
1291     else
1292       unichars[i] = 0xFEFF;
1293   unichars[0x100] = 0;
1295   {
1296 #ifdef NS_IMPL_COCOA
1297     NSString *allChars = [[NSString alloc]
1298                                initWithCharactersNoCopy: unichars
1299                                                  length: 0x100
1300                                            freeWhenDone: NO];
1301     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1302     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1303     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1304     unsigned int gInd =0, cInd =0;
1306     [glyphStorage setString: allChars font: font_info->nsfont];
1307     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1308                         desiredNumberOfCharacters: glyphStorage->maxChar
1309                                        glyphIndex: &gInd characterIndex: &cInd];
1310 #endif
1311     glyphs = font_info->glyphs[block];
1312     for (i =0; i<0x100; i++, glyphs++)
1313       {
1314 #ifdef NS_IMPL_GNUSTEP
1315         g = unichars[i];
1316 #else
1317         g = glyphStorage->cglyphs[i];
1318         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1319         if (g > numGlyphs)
1320           g = 0xFFFF; /* hopefully unused... */
1321 #endif
1322         *glyphs = g;
1323       }
1325 #ifdef NS_IMPL_COCOA
1326     [allChars release];
1327 #endif
1328   }
1330   UNBLOCK_INPUT;
1331   xfree (unichars);
1335 /* Determine and cache metrics for corresponding glyph codes in given
1336    hi-byte block of 256. */
1337 static void
1338 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1340   unsigned int i, g;
1341   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1342   NSFont *sfont;
1343   struct font_metrics *metrics;
1345   if (NSFONT_TRACE)
1346     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1347             font_info, block);
1349 #ifdef NS_IMPL_GNUSTEP
1350   /* not implemented yet (as of startup 0.18), so punt */
1351   if (numGlyphs == 0)
1352     numGlyphs = 0x10000;
1353 #endif
1355  BLOCK_INPUT;
1356  sfont = [font_info->nsfont screenFont];
1358   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1359   bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1360   if (!(font_info->metrics[block]))
1361     abort ();
1363   metrics = font_info->metrics[block];
1364   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1365     {
1366       float w, lb, rb;
1367       NSRect r = [sfont boundingRectForGlyph: g];
1369 #ifdef NS_IMPL_GNUSTEP
1370       {
1371         /* lord help us */
1372         NSString *s = [NSString stringWithFormat: @"%c", g];
1373         w = [sfont widthOfString: s];
1374       }
1375 #else
1376       w = [sfont advancementForGlyph: g].width;
1377 #endif
1378       w = max (w, 2.0);
1379       metrics->width = lrint (w);
1381       lb = r.origin.x;
1382       rb = r.size.width - w;
1383       if (lb < 0)
1384         metrics->lbearing = round (lb);
1385       if (font_info->ital)
1386         rb += 0.22 * font_info->height;
1387       metrics->rbearing = lrint (w + rb);
1389       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1390  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1391       metrics->ascent = r.size.height - metrics->descent;
1392 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1393     }
1394   UNBLOCK_INPUT;
1398 #ifdef NS_IMPL_COCOA
1399 /* helper for font glyph setup */
1400 @implementation EmacsGlyphStorage
1402 - init
1404   return [self initWithCapacity: 1024];
1407 - initWithCapacity: (unsigned long) c
1409   self = [super init];
1410   maxChar = 0;
1411   maxGlyph = 0;
1412   dict = [NSMutableDictionary new];
1413   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1414   return self;
1417 - (void) dealloc
1419   if (attrStr != nil)
1420     [attrStr release];
1421   [dict release];
1422   xfree (cglyphs);
1423   [super dealloc];
1426 - (void) setString: (NSString *)str font: (NSFont *)font
1428   [dict setObject: font forKey: NSFontAttributeName];
1429   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1430   maxChar = [str length];
1431   maxGlyph = 0;
1434 /* NSGlyphStorage protocol */
1435 - (unsigned int)layoutOptions
1437   return 0;
1440 - (NSAttributedString *)attributedString
1442   return attrStr;
1445 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1446         forStartingGlyphAtIndex: (unsigned int)glyphIndex
1447         characterIndex: (unsigned int)charIndex
1449   len = glyphIndex+length;
1450   for (i =glyphIndex; i<len; i++)
1451     cglyphs[i] = glyphs[i-glyphIndex];
1452   if (len > maxGlyph)
1453     maxGlyph = len;
1456 - (void)setIntAttribute: (int)attributeTag value: (int)val
1457         forGlyphAtIndex: (unsigned)glyphIndex
1459   return;
1462 @end
1463 #endif /* NS_IMPL_COCOA */
1466 /* Debugging */
1467 void
1468 dump_glyphstring (struct glyph_string *s)
1470   int i;
1472   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1473            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1474            s->row->overlapping_p, s->background_filled_p);
1475   for (i =0; i<s->nchars; i++)
1476     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1477   fprintf (stderr, "\n");
1482 void
1483 syms_of_nsfont ()
1485   nsfont_driver.type = Qns;
1486   register_font_driver (&nsfont_driver, NULL);
1487   DEFSYM (Qapple, "apple");
1488   DEFSYM (Qroman, "roman");
1489   DEFSYM (Qmedium, "medium");
1492 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae