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