(diff-auto-refine-mode): Remove lighter, since it's
[emacs.git] / src / nsfont.m
blobf206e0d27b267456d78db9626c47984b37e4f2cc
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 : NSUnboldFontMask;
126   n = FONT_SLANT_NUMERIC (font_spec);
127   if (n != -1)
128       traits |= (n > STYLE_REF) ? NSItalicFontMask : NSUnitalicFontMask;
130   n = FONT_WIDTH_NUMERIC (font_spec);
131   if (n > -1)
132     {
133       if (n < STYLE_REF - 10)
134         traits |= NSCondensedFontMask;
135       else if (n > STYLE_REF + 10)
136         traits |= NSExpandedFontMask;
137     }
139 /*fprintf (stderr, "  returning traits = %u\n", traits); */
140   return traits;
144 /* Converts NSArray of PS name, non-family part, weight, and traits to a
145    font backend font-entity. */
146 static Lisp_Object
147 nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
149   Lisp_Object font_entity = font_make_entity ();
150   unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
151 /*   NSString *psName = [famMember objectAtIndex: 0]; */
152   NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
153   char *escapedFamily = strdup ([family UTF8String]);
155   nsfont_escape_name (escapedFamily);
156   [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
157                                range: NSMakeRange (0, [suffix length])];
159   ASET (font_entity, FONT_TYPE_INDEX, Qns);
160   ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
161   ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
162   ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
163   ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
165   FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
166       traits & NSBoldFontMask ? Qbold : Qmedium);
167   FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
168       traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
169   FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
170       traits & NSCondensedFontMask ? Qcondensed :
171         traits & NSExpandedFontMask ? Qexpanded : Qnormal);
173   ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
174   ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
175   ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
177   if (NSFONT_TRACE)
178     {
179       fprintf (stderr, "created font_entity:\n    ");
180       debug_print (font_entity);
181      }
183   [suffix release];
184   free (escapedFamily);
185   return font_entity;
189 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
190 static int
191 nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
193   int i, d =0;
194   for (i =0; i<sizeof (unsigned int)*8; i++)
195     {
196       d += (traits1 & 0x1) ^ (traits2 & 0x1);
197       traits1 >> 1;
198       traits2 >> 1;
199     }
200   return d;
204 /* Default font entity based on Monaco. */
205 static Lisp_Object
206 nsfont_fallback_entity ()
208   NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
209   NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
210                                     [NSNumber numberWithUnsignedInt: 5],
211                                     [NSNumber numberWithUnsignedInt: 0], nil];
212   return nsfont_fmember_to_entity (family, famMemberSpec);
216 /* ==========================================================================
218     Font driver implementation
220    ========================================================================== */
222 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
223 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
224 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
225 static Lisp_Object nsfont_list_family (Lisp_Object frame);
226 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
227                                  int pixel_size);
228 static void nsfont_close (FRAME_PTR f, struct font *font);
229 static int nsfont_has_char (Lisp_Object entity, int c);
230 static unsigned int nsfont_encode_char (struct font *font, int c);
231 static int nsfont_text_extents (struct font *font, unsigned int *code,
232                                 int nglyphs, struct font_metrics *metrics);
233 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
234                         int with_background);
236 struct font_driver nsfont_driver =
237   {
238     0,                          /* Qns */
239     1,                          /* case sensitive */
240     nsfont_get_cache,
241     nsfont_list,
242     nsfont_match,
243     nsfont_list_family,
244     NULL,                       /*free_entity */
245     nsfont_open,
246     nsfont_close,
247     NULL,                       /* prepare_face */
248     NULL,                       /* done_face */
249     nsfont_has_char,
250     nsfont_encode_char,
251     nsfont_text_extents,
252     nsfont_draw,
253     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
254                  anchor_point, otf_capability, otf_driver,
255                  start_for_frame, end_for_frame, shape */
256   };
259 /* Return a cache of font-entities on FRAME.  The cache must be a
260    cons whose cdr part is the actual cache area.  */
261 static Lisp_Object
262 nsfont_get_cache (FRAME_PTR frame)
264   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
265   return (dpyinfo->name_list_element);
269 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value
270    is a vector of font-entities.  This is the sole API that
271    allocates font-entities.  */
272 static Lisp_Object
273 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
275   Lisp_Object list = Qnil;
276   Lisp_Object tem;
277   NSString *family;
278   NSArray *families;
279   NSEnumerator *famEnum;
280   NSFontManager *fontMgr;
281   unsigned int traits = nsfont_spec_to_traits (font_spec);
283   if (NSFONT_TRACE)
284     {
285       fprintf (stderr, "nsfont: list for fontspec:\n    ");
286       debug_print (font_spec);
287     }
289   /* if has non-unicode registry, give up */
290   tem = AREF (font_spec, FONT_REGISTRY_INDEX);
291   if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
292     return Qnil;
294   fontMgr = [NSFontManager sharedFontManager];
296   family = nsfont_get_family (font_spec);
298   if (family != nil)
299     families = [NSArray arrayWithObject: family];
300   else
301     families = [fontMgr availableFontFamilies];
303   for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
304     {
305       NSEnumerator *fm;
306       NSArray *fmember, *firstMember = nil;
307       unsigned int mtraits;
308       BOOL foundItal = NO || (traits & NSUnitalicFontMask);
309       NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
310 #ifdef NS_IMPL_COCOA
311       /* LastResort is special: not a family but a font name only */
312       if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
313         {
314           famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
315               @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
316               [NSNumber numberWithUnsignedInt: 0], nil]];
317         }
318 #endif
320       /* fmember = [postscriptName style weight traits] */
321       fm  = [famMembers objectEnumerator];
322       while (fmember = [fm nextObject])
323         {
324           mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
325           if ((mtraits & traits) == traits)
326             {
327               list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
328               if (mtraits & NSItalicFontMask)
329                 foundItal = YES;
330               if (firstMember == nil)
331                 firstMember = fmember;
332             }
333         }
334       if (foundItal == NO && firstMember != nil)
335         {
336           /* no italic member found; add a synthesized one */
337           NSMutableArray *smember = [firstMember mutableCopy];
338           [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
339           mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
340           mtraits |= NSItalicFontMask;
341           [smember replaceObjectAtIndex: 3
342                    withObject: [NSNumber numberWithUnsignedInt: mtraits]];
343 /*NSLog (@"-- adding synthItal member: %@", smember); */
344           list = Fcons (nsfont_fmember_to_entity (family, smember), list);
345           [smember release];
346         }
347     }
349   if (NSFONT_TRACE)
350       fprintf (stderr, "    Returning %d entities.\n", XINT (Flength (list)));
352   return (NILP (list) ? Qnil : Fvconcat (1, &list));/* Qnil was null_vector */
356 /* Return a font entity most closely maching with FONT_SPEC on
357    FRAME.  The closeness is determined by the font backend, thus
358    `face-font-selection-order' is ignored here.  */
359 static Lisp_Object
360 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
362   long traits = nsfont_spec_to_traits (font_spec);
363   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
364   NSString *family;
365   Lisp_Object tem;
367   if (NSFONT_TRACE)
368     {
369       fprintf (stderr, "nsfont: match for fontspec:\n    ");
370       debug_print (font_spec);
371     }
373   /* if has non-unicode registry, just return fallback */
374 #if 0
375   tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
376   if (!NILP (tem))
377     fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
378 #endif
379   tem = AREF (font_spec, FONT_REGISTRY_INDEX);
380   if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
381     return nsfont_fallback_entity ();
383   family = nsfont_get_family (font_spec);
385   if (family != nil)
386     {
387       /* try to find close font in family */
388       NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
389       NSEnumerator *fm = [famMembers objectEnumerator];
390       NSArray *fmember;
391       int minDist = sizeof (unsigned int) * 8 + 1;
392       int bestMatchIdx = -1;
393       int i;
395       for (i =0; fmember = [fm nextObject]; i++)
396         {
397           unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
398           int dist = nsfont_trait_distance ((mtraits & traits), traits);
399           if (dist < minDist)
400             {
401               bestMatchIdx = i;
402               minDist = dist;
403             }
404         }
405       if (bestMatchIdx != -1)
406         return nsfont_fmember_to_entity
407           (family, [famMembers objectAtIndex: bestMatchIdx]);
408     }
410   /* no family that had members was given; find any font matching traits */
411   {
412     NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
413     if (fontNames && [fontNames count]  > 0)
414       {
415         NSString *fontName = [fontNames objectAtIndex: 0];
416         /* XXX: is there a more efficient way to get family name? */
417         NSFont *font = [NSFont fontWithName: fontName size: 0];
418         if (font != nil)
419           {
420             /* now need to get suffix part of name.. */
421             NSString *family = [font familyName];
422             NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
423                                  objectEnumerator];
424             NSArray *fmember;
425             while (fmember = [fm nextObject])
426               {
427                 unsigned int mtraits =
428                   [[fmember objectAtIndex: 3] unsignedIntValue];
429                 if (mtraits & traits == traits)
430                   return nsfont_fmember_to_entity (family, fmember);
431               }
432           }
433       }
434   }
436   /* if we get here, return the fallback */
437   if (NSFONT_TRACE)
438       fprintf (stderr, "    *** returning fallback\n");
440   return nsfont_fallback_entity ();
444 /* List available families.  The value is a list of family names
445    (symbols). */
446 static Lisp_Object
447 nsfont_list_family (Lisp_Object frame)
449   Lisp_Object list = Qnil;
450   NSEnumerator *families =
451     [[[NSFontManager sharedFontManager] availableFontFamilies]
452       objectEnumerator];
453   NSString *family;
454   while (family = [families nextObject])
455       list = Fcons (intern ([family UTF8String]), list);
456   /* FIXME: escape the name? */
458   if (NSFONT_TRACE)
459     fprintf (stderr, "nsfont: list families returning %d entries\n",
460             XINT (Flength (list)));
462   return list;
466 /* utility: get width of a char c in screen font sfont */
467 static float
468 nsfont_char_width (NSFont *sfont, int c)
470   float w;
471   NSString *cstr = [NSString stringWithFormat: @"%c", c];
472 #ifdef NS_IMPL_COCOA
473   NSGlyph glyph = [sfont glyphWithName: cstr];
474   if (glyph)
475     {
476       float w = [sfont advancementForGlyph: glyph].width;
477       if (w >= 1.5)
478         return w;
479     }
480 #endif
481   w = [sfont widthOfString: cstr];
482   return max (w, 2.0);
486 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
487    scalable, open it with PIXEL_SIZE.  */
488 static Lisp_Object
489 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
491   BOOL synthItal;
492   struct nsfont_info *font_info;
493   struct font *font;
494   unsigned int traits = nsfont_spec_to_traits (font_entity);
495   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
496   NSString *family;
497   NSFont *nsfont, *sfont;
498   Lisp_Object tem;
499   NSRect brect;
500   Lisp_Object font_object;
501   int i;
502   int fixLeopardBug;
503 #if 0
504   static NSMutableDictionary *fontCache = nil;
506   /* 2008/03/08: The same font may end up being requested for different
507      entities, due to small differences in numeric values or other issues,
508      or for different copies of the same entity.  Therefore we cache to
509      avoid creating multiple struct font objects (with metrics cache, etc.)
510      for the same NSFont object.
511      2008/06/01: This is still an issue, but after font backend refactoring
512      caching will be more difficult, needs to be reworked before enabling. */
513   if (fontCache == nil)
514     fontCache = [[NSMutableDictionary alloc] init];
515 #endif
517   font_object = font_make_object (VECSIZE (struct nsfont_info), font_entity,
518                                   pixel_size);
519   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
520   font = (struct font *)font_info;
521   if (!font)
522     return Qnil; /* FIXME: this copies w32, but causes a segfault */
524   if (NSFONT_TRACE)
525     {
526       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
527       debug_print (font_entity);
528     }
530   if (pixel_size <= 0)
531     {
532       /* try to get it out of frame params */
533         Lisp_Object tem = get_frame_param (f, Qfontsize);
534         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
535     }
537   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
538   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
539                                        9);
540   family = nsfont_get_family (font_entity);
541   if (NSFONT_TRACE)
542     {
543       fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\n",
544                [family UTF8String], traits, traits & NSBoldFontMask);
545     }
547   /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
548   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
549   nsfont = [fontMgr fontWithFamily: family
550                             traits: traits weight: fixLeopardBug
551                               size: pixel_size];
552   /* if didn't find, try synthetic italic */
553   if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
554     {
555       nsfont = [fontMgr fontWithFamily: family
556                                 traits: traits & ~NSItalicFontMask
557                                 weight: fixLeopardBug size: pixel_size];
558     }
559 #ifdef NS_IMPL_COCOA
560   /* LastResort not really a family */
561   if (nsfont == nil && [@"LastResort" isEqualToString: family])
562     {
563       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
564     }
565 #endif
567   if (nsfont == nil)
568     {
569       message_with_string ("*** Warning: font in family '%s' not found",
570                           build_string ([family UTF8String]), 1);
571       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
572       if (!nsfont)
573         {
574           fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
575           return Qnil;
576         }
577     }
579 #if 0
580   {
581     NSNumber *cached = [fontCache objectForKey: nsfont];
582     if (cached != nil && !synthItal)
583       {
584 fprintf (stderr, "*** CACHE HIT!\n");
585         struct font_info *existing =
586           (struct nsfont_info *)[cached unsignedLongValue];
587         /* ... */
588       }
589     else
590       {
591         if (!synthItal)
592           [fontCache
593             setObject: [NSNumber numberWithUnsignedLong:
594                                    (unsigned long)font_info]
595                forKey: nsfont];
596       }
597   }
598 #endif
600   font_info->glyphs = (unsigned short *)
601     xmalloc (0x100 * sizeof (unsigned short *));
602   font_info->metrics = (struct font_metrics *)
603     xmalloc (0x100 * sizeof (struct font_metrics *));
604   if (!font_info->glyphs || !font_info->metrics)
605     return Qnil;
606   bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
607   bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
610 BLOCK_INPUT;
612   /* for metrics */
613   sfont = [nsfont screenFont];
614   if (sfont == nil)
615     sfont = nsfont;
617   /* non-metric backend font struct fields */
618   font = (struct font *) font_info;
619   font->pixel_size = [sfont pointSize];
620   font->driver = &nsfont_driver;
621   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
622   font->encoding_charset = -1;
623   font->repertory_charset = -1;
624   font->default_ascent = 0;
625   font->vertical_centering = 0;
626   font->baseline_offset = 0;
627   font->relative_compose = 0;
628   font->font_encoder = NULL;
630   /* TODO: does anything care about this? */
631   font->props[FONT_FORMAT_INDEX] = Qns;
632   font->props[FONT_FILE_INDEX] = Qnil;
634   {
635     double expand, shrink, hshrink;
636     float full_height, min_height, hd;
637     const char *fontName = [[nsfont fontName] UTF8String];
638     int len = strlen (fontName);
640 #ifdef NS_IMPL_GNUSTEP
641     font_info->nsfont = sfont;
642 #else
643     font_info->nsfont = nsfont;
644 #endif
645     [font_info->nsfont retain];
647     /* set up ns_font (defined in nsgui.h) */
648     font_info->name = (char *)xmalloc (strlen (fontName)+1);
649     bcopy (fontName, font_info->name, strlen (fontName)+1);
650     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
651     font_info->ital =
652       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
654     /* Metrics etc.; some fonts return an unusually large max advance, so we
655        only use it for fonts that have wide characters. */
656     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
657       [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
659     brect =  [sfont boundingRectForFont];
660     full_height = brect.size.height;
661     min_height = [sfont ascender] - [sfont descender];
662     hd = full_height - min_height;
664     if (!NUMBERP (ns_expand_space))
665       error ("No expand space defined");
667     /* ns_expand_space = 0.0 is use standard height; less shrink, more expand */
668     expand = XFLOATINT (ns_expand_space) + 0.5;
670     if (expand < 0.0)
671       {
672         shrink = 1 + expand;
673         hshrink = 1 + expand / 2.0;
674         expand = 0.0;
675       }
676     else
677       shrink = hshrink = 1.0;
679     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
680     font_info->underwidth = [sfont underlineThickness];
681     font_info->size = font->pixel_size;
682     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
684     /* max bounds */
685     font_info->max_bounds.ascent =
686       lrint (hshrink * [sfont ascender] + expand * hd/2);
687     font_info->max_bounds.descent =
688       -lrint (hshrink* [sfont descender] - expand*hd/2);
689     font_info->height =
690       font_info->max_bounds.ascent + font_info->max_bounds.descent;
691     font_info->max_bounds.width = lrint (font_info->width);
692     font_info->max_bounds.lbearing = lrint (brect.origin.x);
693     font_info->max_bounds.rbearing =
694       lrint (brect.size.width - font_info->width);
695       /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
697 #ifdef NS_IMPL_COCOA
698     /* set up synthItal and the CG font */
699     font_info->synthItal = synthItal;
700     {
701       ATSFontRef atsFont = ATSFontFindFromPostScriptName
702         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
704       if (atsFont == kATSFontRefUnspecified)
705         {
706           /* see if we can get it by dropping italic (then synthesizing) */
707           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
708               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
709                 fontName], kATSOptionFlagsDefault);
710           if (atsFont != kATSFontRefUnspecified)
711               font_info->synthItal = YES;
712           else
713             {
714               /* last resort fallback */
715               atsFont = ATSFontFindFromPostScriptName
716                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
717             }
718         }
719       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
720     }
721 #endif
723     /* set up metrics portion of font struct */
724     font->ascent = [sfont ascender];
725     font->descent = -[sfont descender];
726     font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
727     font->space_width = lrint (nsfont_char_width (sfont, ' '));
728     font->average_width = lrint (font_info->width);
729     font->max_width = lrint (font_info->max_bounds.width);
730     font->height = lrint (font_info->height);
731     font->underline_position = lrint (font_info->underpos);
732     font->underline_thickness = lrint (font_info->underwidth);
734     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
735     font->props[FONT_FULLNAME_INDEX] =
736       make_unibyte_string (font_info->name, strlen (font_info->name));
737   }
738   UNBLOCK_INPUT;
740   return font_object;
744 /* Close FONT on frame F. */
745 static void
746 nsfont_close (FRAME_PTR f, struct font *font)
748   struct nsfont_info *font_info = (struct nsfont_info *)font;
749   int i;
751   /* FIXME: this occurs apparently due to same failure to detect same font
752             that causes need for cache in nsfont_open ()
753             (came after unicode-2 -> trunk) */
754   if (!font_info)
755       return;
757   for (i =0; i<0x100; i++)
758     {
759       if (font_info->glyphs[i])
760         xfree (font_info->glyphs[i]);
761       if (font_info->metrics[i])
762         xfree (font_info->metrics[i]);
763     }
764   [font_info->nsfont release];
765 #ifdef NS_IMPL_COCOA
766       CGFontRelease (font_info->cgfont);
767 #endif
768       xfree (font_info->name);
769       xfree (font_info);
773 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
774    return 1.  If not, return 0.  If a font must be opened to check
775    it, return -1. */
776 static int
777 nsfont_has_char (Lisp_Object entity, int c)
779   return -1;
783 /* Return a glyph code of FONT for character C (Unicode code point).
784    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
785 static unsigned int
786 nsfont_encode_char (struct font *font, int c)
788   struct nsfont_info *font_info = (struct nsfont_info *)font;
789   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
790   unsigned short g;
792   if (c > 0xFFFF)
793     return FONT_INVALID_CODE;
795   /* did we already cache this block? */
796   if (!font_info->glyphs[high])
797     ns_uni_to_glyphs (font_info, high);
799   g = font_info->glyphs[high][low];
800 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
801   return g == 0xFFFF ? FONT_INVALID_CODE : g;
805 /* Perform the size computation of glyphs of FONT and fill in members
806    of METRICS.  The glyphs are specified by their glyph codes in
807    CODE (length NGLYPHS). */
808 static int
809 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
810                      struct font_metrics *metrics)
812   struct nsfont_info *font_info = (struct nsfont_info *)font;
813   struct font_metrics *pcm;
814   unsigned char high, low;
815   int totalWidth = 0;
816   int i;
818   bzero (metrics, sizeof (struct font_metrics));
820   for (i =0; i<nglyphs; i++)
821     {
822       /* get metrics for this glyph, filling cache if need be */
823       /* TODO: get metrics for whole string from an NSLayoutManager
824                (if not too slow) */
825       high = (code[i] & 0xFF00) >> 8;
826       low = code[i] & 0x00FF;
827       if (!font_info->metrics[high])
828         ns_glyph_metrics (font_info, high);
829       pcm = &(font_info->metrics[high][low]);
831       if (metrics->lbearing > totalWidth + pcm->lbearing)
832         metrics->lbearing = totalWidth + pcm->lbearing;
833       if (metrics->rbearing < totalWidth + pcm->rbearing)
834         metrics->rbearing = totalWidth + pcm->rbearing;
835       if (metrics->ascent < pcm->ascent)
836         metrics->ascent = pcm->ascent;
837       if (metrics->descent < pcm->descent)
838         metrics->descent = pcm->descent;
840       totalWidth += pcm->width;
841     }
843   metrics->width = totalWidth;
845   return totalWidth; /* not specified in doc, but xfont.c does it */
849 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
850    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
851    is nonzero, fill the background in advance.  It is assured that
852    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
853 static int
854 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
855              int with_background)
856 /* NOTE: focus and clip must be set
857      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
859   static char cbuf[1024];
860   char *c = cbuf;
861 #ifdef NS_IMPL_GNUSTEP
862   static float advances[1024];
863   float *adv = advances;
864 #else
865   static CGSize advances[1024];
866   CGSize *adv = advances;
867 #endif
868   struct face *face;
869   NSRect r;
870   struct nsfont_info *font = ns_tmp_font;
871   NSColor *col, *bgCol;
872   unsigned short *t = s->char2b;
873   int i, len;
875   /* Select face based on input flags */
876   switch (ns_tmp_flags)
877     {
878     case NS_DUMPGLYPH_CURSOR:
879       face = s->face;
880       break;
881     case NS_DUMPGLYPH_MOUSEFACE:
882       face = FACE_FROM_ID (s->f,
883                            FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
884       if (!face)
885         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
886       break;
887     default:
888       face = s->face;
889     }
891   r.origin.x = s->x;
892   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
893     r.origin.x += abs (s->face->box_line_width);
895   r.origin.y = s->y;
896   r.size.height = FONT_HEIGHT (font);
898   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
899      NS to render the string, it will come out differently from the individual
900      character widths added up because of layout processing. */
901   {
902     XCharStruct *cs;
903     int cwidth, twidth = 0;
904     int hi, lo;
905     char isComposite = 0; /* s->first_glyph->type == COMPOSITE_GLYPH; */
906     /* FIXME: composition: no vertical displacement is considered. */
907     t+= s->gidx; /* advance into composition */
908     for (i =0; i<s->nchars - s->gidx; i++, t++)
909       {
910         hi = (*t & 0xFF00) >> 8;
911         lo = *t & 0x00FF;
912         if (isComposite)
913           {
914             cwidth = s->cmp->offsets[s->gidx++ * 2] - twidth;
915           }
916         else
917           {
918             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
919               ns_glyph_metrics (font, hi);
920             cwidth = font->metrics[hi][lo].width;
921           }
922         twidth += cwidth;
923 #ifdef NS_IMPL_GNUSTEP
924         *adv++ = cwidth;
925         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
926 #else
927         (*adv++).width = cwidth;
928 #endif
929       }
930     len = adv - advances;
931     r.size.width = twidth;
932     *c = 0;
933   }
935   /* fill background if requested */
936   if (with_background)
937     {
938       NSRect br = r;
939       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
940       int mbox_line_width = max (s->face->box_line_width, 0);
942       if (s->row->full_width_p)
943         {
944           if (br.origin.x <= fibw + 1 + mbox_line_width)
945             {
946               br.size.width += br.origin.x - mbox_line_width;
947               br.origin.x = mbox_line_width;
948             }
949           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
950                 <= fibw+1)
951             br.size.width += fibw;
952         }
953       if (s->face->box == FACE_NO_BOX)
954         {
955           /* expand unboxed top row over internal border */
956           if (br.origin.y <= fibw + 1 + mbox_line_width)
957             {
958               br.size.height += br.origin.y;
959               br.origin.y = 0;
960             }
961         }
962       else
963         {
964           int correction = abs (s->face->box_line_width)+1;
965           br.origin.y += correction;
966           br.size.height -= 2*correction;
967           br.origin.x += correction;
968           br.size.width -= 2*correction;
969         }
971       if (!s->face->stipple)
972         [(NS_FACE_BACKGROUND (face) != 0
973           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
974           : FRAME_BACKGROUND_COLOR (s->f)) set];
975       else
976         {
977           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
978           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
979         }
980       NSRectFill (br);
981     }
984   /* set up for character rendering */
985   r.origin.y += font->voffset + (s->height - font->height)/2;
987   col = (NS_FACE_FOREGROUND (face) != nil
988          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
989          : FRAME_FOREGROUND_COLOR (s->f));
990   /* FIXME: find another way to pass this */
991   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
992            : (NS_FACE_BACKGROUND (face) != 0
993               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
994               : FRAME_BACKGROUND_COLOR (s->f)));
996   /* render under GNUstep using DPS */
997 #ifdef NS_IMPL_GNUSTEP
998   {
999     NSGraphicsContext *context = GSCurrentContext ();
1001     DPSgsave (context);
1002     [font->nsfont set];
1004     /* do erase if "foreground" mode */
1005     if (bgCol != nil)
1006       {
1007         [bgCol set];
1008         DPSmoveto (context, r.origin.x, r.origin.y);
1009 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1010         DPSxshow (context, cbuf, advances, len);
1011         DPSstroke (context);
1012         [col set];
1013 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1014       }
1016     /* do underline */
1017     if (face->underline_p)
1018       {
1019         if (face->underline_color != nil)
1020           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1021         else
1022           [col set];
1023         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1024         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1025         if (face->underline_color != nil)
1026           [col set];
1027       }
1028     else
1029       [col set];
1031     /* draw with DPSxshow () */
1032     DPSmoveto (context, r.origin.x, r.origin.y);
1033     DPSxshow (context, cbuf, advances, len);
1034     DPSstroke (context);
1036     DPSgrestore (context);
1037     return to-from;
1038   }
1040 #else  /* NS_IMPL_COCOA */
1041   {
1042     CGContextRef gcontext =
1043       [[NSGraphicsContext currentContext] graphicsPort];
1044     static CGAffineTransform fliptf;
1045     static BOOL firstTime = YES;
1047     if (firstTime)
1048       {
1049         firstTime = NO;
1050         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1051       }
1053     CGContextSaveGState (gcontext);
1055     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1057     CGContextSetFont (gcontext, font->cgfont);
1058     CGContextSetFontSize (gcontext, font->size);
1059     if (ns_antialias_text == NO || font->size <= ns_antialias_threshold)
1060       CGContextSetShouldAntialias (gcontext, 0);
1061     else
1062       CGContextSetShouldAntialias (gcontext, 1);
1063     if (EQ (ns_use_qd_smoothing, Qt))
1064       CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1066     CGContextSetTextMatrix (gcontext, fliptf);
1068     if (bgCol != nil)
1069       {
1070         /* foreground drawing; erase first to avoid overstrike */
1071         [bgCol set];
1072         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1073         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1074         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1075         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1076       }
1078     if (face->underline_p)
1079       {
1080         if (face->underline_color != nil)
1081           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1082         else
1083           [col set];
1084         CGContextBeginPath (gcontext);
1085         CGContextMoveToPoint (gcontext,
1086                               r.origin.x, r.origin.y + font->underpos);
1087         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1088                                 r.origin.y + font->underpos);
1089         CGContextStrokePath (gcontext);
1090         if (face->underline_color != nil)
1091           [col set];
1092       }
1093     else
1094       [col set];
1096     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1097     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->gidx,
1098                                     advances, len);
1100     if (face->overstrike)
1101       {
1102         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1103         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->gidx,
1104                                         advances, len);
1105       }
1107     CGContextRestoreGState (gcontext);
1108     return;
1109   }
1110 #endif  /* NS_IMPL_COCOA */
1115 /*  Auto-creates a fontset built around the font in font_object,
1116     by creating an attributed string with characters from each
1117     script, then requesting the NS text system to fix attributes
1118     in range. */
1119 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1121   Lisp_Object script, famAndReg;
1122   struct nsfont_info *font_info =
1123     (struct nsfont_info *)XFONT_OBJECT (font_object);
1125   /* NS text system (and char buf) init */
1126   static NSTextStorage *store;
1127   static NSLayoutManager *layout;
1128   static NSRange range;
1129   static NSMutableDictionary *attribs;
1130   static Lisp_Object *scripts;
1131   static int nscripts;
1132   static int *scriptsNchars;
1133   static BOOL firstTime = YES;
1134   Lisp_Object regString = build_string ("iso10646-1");
1135   int i, j;
1137   if (firstTime == YES)
1138     {
1139       nscripts = XINT (Flength (Vscript_representative_chars));
1140       scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1141       unsigned char *buf = malloc (4*nscripts*sizeof (char));
1142       Lisp_Object scriptsChars = Vscript_representative_chars;
1143       unsigned char *tpos = buf;
1145       scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1147       for (i =0; i<nscripts; i++)
1148         {
1149           Lisp_Object sChars = XCAR (scriptsChars);
1150           Lisp_Object chars = XCDR (sChars);
1151           unsigned int ch, c =0;
1152           scripts[i] = XCAR (sChars);
1154           while (CONSP (chars))
1155             {
1156               ch = XUINT (XCAR (chars));
1157               chars = XCDR (chars);
1158               CHAR_STRING_ADVANCE (ch, tpos);
1159               c++;
1160             }
1161           scriptsNchars[i] = c;
1163           scriptsChars = XCDR (scriptsChars);
1164         }
1165       *tpos = '\0';
1167       store = [[NSTextStorage alloc] init];
1168       layout = [[NSLayoutManager alloc] init];
1169       [store addLayoutManager: layout];
1170       [layout release];
1172       [store beginEditing];
1173       [[store mutableString] appendString:
1174                                [NSString stringWithUTF8String: buf]];
1175       [store endEditing];
1177       free (buf);
1178       range = NSMakeRange (0, [store length]);
1180       attribs = [[NSMutableDictionary alloc] init];
1181       firstTime = NO;
1182     }
1184   /* set the fonts */
1185   [store beginEditing];
1186   [store removeAttribute: NSFontAttributeName range: range];
1187   [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1188   [store addAttributes: attribs range: range];
1189   [store endEditing];
1191   /* read them out */
1192   {
1193     NSMutableDictionary *map =
1194       [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1195     NSEnumerator *fonts;
1196     NSFont *cfont = nil, *tfont;
1197     NSNumber *n;
1198     int idx = 0;
1199     int max;
1200     for (i =0; i<nscripts; i++)
1201       {
1202         [map removeAllObjects];
1203         for (j =0; j<scriptsNchars[i]; j++)
1204           {
1205             cfont = [store attribute: NSFontAttributeName atIndex: idx++
1206                       effectiveRange: NULL];
1207             n = [map objectForKey: cfont];
1208             if (n == nil)
1209               n = [NSNumber numberWithInt: 1];
1210             else
1211               n = [NSNumber numberWithInt: [n intValue] + 1];
1212             [map setObject: n forKey: cfont];
1213           }
1215         /* majority rules */
1216         max = 0;
1217         fonts = [map keyEnumerator];
1218         while (tfont = [fonts nextObject])
1219           {
1220             n = [map objectForKey: tfont];
1221             if ([n intValue] > max)
1222               {
1223                 cfont = tfont;
1224                 max = [n intValue];
1225               }
1226           }
1228         if (cfont != nil)
1229           {
1230             char *family = strdup([[cfont familyName] UTF8String]);
1231             Lisp_Object famAndReg;
1233             nsfont_escape_name (family);
1234             famAndReg = Fcons (build_string (family), regString);
1236             if (NSFONT_TRACE)
1237               fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1238                       font_info->name, family,
1239                        SDATA (SYMBOL_NAME (scripts[i])));
1241             Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1242             free (family);
1243           }
1244         else
1245           {
1246             fprintf (stderr, "%s fontset: none found for script '%s'\n",
1247                     font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1248          }
1249       }  /* for i = script */
1250   }
1255 /* ==========================================================================
1257     Font glyph and metrics caching functions
1259    ========================================================================== */
1261 /* Find and cache corresponding glyph codes for unicode values in given
1262    hi-byte block of 256. */
1263 static void
1264 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1266 #ifdef NS_IMPL_COCOA
1267   static EmacsGlyphStorage *glyphStorage;
1268   static char firstTime = 1;
1269 #endif
1270   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1271   unsigned int i, g, idx;
1272   unsigned short *glyphs;
1274   if (NSFONT_TRACE)
1275     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1276             font_info, block);
1278  BLOCK_INPUT;
1280 #ifdef NS_IMPL_COCOA
1281   if (firstTime)
1282     {
1283       firstTime = 0;
1284       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1285     }
1286 #endif
1288   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1289   if (!unichars || !(font_info->glyphs[block]))
1290     abort ();
1292   /* create a string containing all unicode characters in this block */
1293   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1294     if (idx < 0xD800 || idx > 0xDFFF)
1295       unichars[i] = idx;
1296     else
1297       unichars[i] = 0xFEFF;
1298   unichars[0x100] = 0;
1300   {
1301 #ifdef NS_IMPL_COCOA
1302     NSString *allChars = [[NSString alloc]
1303                                initWithCharactersNoCopy: unichars
1304                                                  length: 0x100
1305                                            freeWhenDone: NO];
1306     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1307     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1308     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1309     unsigned int gInd =0, cInd =0;
1311     [glyphStorage setString: allChars font: font_info->nsfont];
1312     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1313                         desiredNumberOfCharacters: glyphStorage->maxChar
1314                                        glyphIndex: &gInd characterIndex: &cInd];
1315 #endif
1316     glyphs = font_info->glyphs[block];
1317     for (i =0; i<0x100; i++, glyphs++)
1318       {
1319 #ifdef NS_IMPL_GNUSTEP
1320         g = unichars[i];
1321 #else
1322         g = glyphStorage->cglyphs[i];
1323         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1324         if (g > numGlyphs)
1325           g = 0xFFFF; /* hopefully unused... */
1326 #endif
1327         *glyphs = g;
1328       }
1330 #ifdef NS_IMPL_COCOA
1331     [allChars release];
1332 #endif
1333   }
1335   UNBLOCK_INPUT;
1336   xfree (unichars);
1340 /* Determine and cache metrics for corresponding glyph codes in given
1341    hi-byte block of 256. */
1342 static void
1343 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1345   unsigned int i, g;
1346   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1347   NSFont *sfont;
1348   struct font_metrics *metrics;
1350   if (NSFONT_TRACE)
1351     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1352             font_info, block);
1354 #ifdef NS_IMPL_GNUSTEP
1355   /* not implemented yet (as of startup 0.18), so punt */
1356   if (numGlyphs == 0)
1357     numGlyphs = 0x10000;
1358 #endif
1360  BLOCK_INPUT;
1361  sfont = [font_info->nsfont screenFont];
1363   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1364   bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1365   if (!(font_info->metrics[block]))
1366     abort ();
1368   metrics = font_info->metrics[block];
1369   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1370     {
1371       float w, lb, rb;
1372       NSRect r = [sfont boundingRectForGlyph: g];
1374 #ifdef NS_IMPL_GNUSTEP
1375       {
1376         /* lord help us */
1377         NSString *s = [NSString stringWithFormat: @"%c", g];
1378         w = [sfont widthOfString: s];
1379       }
1380 #else
1381       w = [sfont advancementForGlyph: g].width;
1382 #endif
1383       w = max (w, 2.0);
1384       metrics->width = lrint (w);
1386       lb = r.origin.x;
1387       rb = r.size.width - w;
1388       if (lb < 0)
1389         metrics->lbearing = round (lb);
1390       if (font_info->ital)
1391         rb += 0.22 * font_info->height;
1392       metrics->rbearing = lrint (w + rb);
1394       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1395  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1396       metrics->ascent = r.size.height - metrics->descent;
1397 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1398     }
1399   UNBLOCK_INPUT;
1403 #ifdef NS_IMPL_COCOA
1404 /* helper for font glyph setup */
1405 @implementation EmacsGlyphStorage
1407 - init
1409   return [self initWithCapacity: 1024];
1412 - initWithCapacity: (unsigned long) c
1414   self = [super init];
1415   maxChar = 0;
1416   maxGlyph = 0;
1417   dict = [NSMutableDictionary new];
1418   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1419   return self;
1422 - (void) dealloc
1424   if (attrStr != nil)
1425     [attrStr release];
1426   [dict release];
1427   xfree (cglyphs);
1428   [super dealloc];
1431 - (void) setString: (NSString *)str font: (NSFont *)font
1433   [dict setObject: font forKey: NSFontAttributeName];
1434   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1435   maxChar = [str length];
1436   maxGlyph = 0;
1439 /* NSGlyphStorage protocol */
1440 - (unsigned int)layoutOptions
1442   return 0;
1445 - (NSAttributedString *)attributedString
1447   return attrStr;
1450 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1451         forStartingGlyphAtIndex: (unsigned int)glyphIndex
1452         characterIndex: (unsigned int)charIndex
1454   len = glyphIndex+length;
1455   for (i =glyphIndex; i<len; i++)
1456     cglyphs[i] = glyphs[i-glyphIndex];
1457   if (len > maxGlyph)
1458     maxGlyph = len;
1461 - (void)setIntAttribute: (int)attributeTag value: (int)val
1462         forGlyphAtIndex: (unsigned)glyphIndex
1464   return;
1467 @end
1468 #endif /* NS_IMPL_COCOA */
1471 /* Debugging */
1472 void
1473 dump_glyphstring (struct glyph_string *s)
1475   int i;
1477   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1478            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1479            s->row->overlapping_p, s->background_filled_p);
1480   for (i =0; i<s->nchars; i++)
1481     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1482   fprintf (stderr, "\n");
1487 void
1488 syms_of_nsfont ()
1490   nsfont_driver.type = Qns;
1491   register_font_driver (&nsfont_driver, NULL);
1492   DEFSYM (Qapple, "apple");
1493   DEFSYM (Qroman, "roman");
1494   DEFSYM (Qmedium, "medium");
1497 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae