Add arch tagline
[emacs.git] / src / nsfont.m
blobbf77d235dd25352a0b5502badee47b49021c5f52
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, or (at your option)
10 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; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
22 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
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 ns_expand_space;
46 extern Lisp_Object Qappend;
47 extern int ns_antialias_text, ns_use_qd_smoothing;
48 extern float ns_antialias_threshold;
49 extern int ns_tmp_flags;
50 extern struct nsfont_info *ns_tmp_font;
52 /* font glyph and metrics caching functions, implemented at end */
53 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
54                               unsigned char block);
55 static void ns_glyph_metrics (struct nsfont_info *font_info,
56                               unsigned char block);
59 /* ==========================================================================
61     Utilities
63    ========================================================================== */
66 /* Replace spaces w/another character so emacs core font parsing routines
67    aren't thrown off. */
68 static void
69 nsfont_escape_name (char *name)
71   int i =0, len =strlen (name);
72   for ( ; i<len; i++)
73     if (name[i] == ' ')
74       name[i] = '_';
78 /* Reconstruct spaces in a font family name passed through emacs. */
79 static void
80 nsfont_unescape_name (char *name)
82   int i =0, len =strlen (name);
83   for ( ; i<len; i++)
84     if (name[i] == '_')
85       name[i] = ' ';
89 /* Extract family name from a font spec. */
90 static NSString *
91 nsfont_get_family (Lisp_Object font_spec)
93   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
94   if (NILP (tem))
95       return nil;
96   else
97     {
98       char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
99       NSString *family;
100       nsfont_unescape_name (tmp);
101       /* PENDING: this seems to be needed only for font names that are
102          hard-coded into emacs, like 'helvetica' for splash screen */
103       if (tmp)
104         tmp[0] = toupper (tmp[0]);
105       family = [NSString stringWithUTF8String: tmp];
106       free (tmp);
107       return family;
108     }
112 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
113 /* PENDING (20080601): The font backend's strategy for handling font
114            styles continues to evolve.  When/if this stabilizes, we
115            can change the code here to be more sophisticated and accurate.
116            For now, we rely on "normal/plain" style being numeric 100. */
117 #define STYLE_REF 100
118 static unsigned int
119 nsfont_spec_to_traits (Lisp_Object font_spec)
121   unsigned int traits = 0;
122   int n;
124   n = FONT_WEIGHT_NUMERIC (font_spec);
125   if (n != -1)
126       traits |= (n > STYLE_REF) ? NSBoldFontMask : NSUnboldFontMask;
128   n = FONT_SLANT_NUMERIC (font_spec);
129   if (n != -1)
130       traits |= (n > STYLE_REF) ? NSItalicFontMask : NSUnitalicFontMask;
132   n = FONT_WIDTH_NUMERIC (font_spec);
133   if (n > -1)
134     {
135       if (n < STYLE_REF - 10)
136         traits |= NSCondensedFontMask;
137       else if (n > STYLE_REF + 10)
138         traits |= NSExpandedFontMask;
139     }
141 /*fprintf (stderr, "  returning traits = %u\n", traits); */
142   return traits;
146 /* Converts NSArray of PS name, non-family part, weight, and traits to a
147    font backend font-entity. */
148 static Lisp_Object
149 nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
151   Lisp_Object font_entity = font_make_entity ();
152   unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
153 /*   NSString *psName = [famMember objectAtIndex: 0]; */
154   NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
155   char *escapedFamily = [family UTF8String];
157   nsfont_escape_name (escapedFamily);
158   [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
159                                range: NSMakeRange (0, [suffix length])];
161   ASET (font_entity, FONT_TYPE_INDEX, Qns);
162   ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
163   ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
164   ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
165   ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
167   FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
168       traits & NSBoldFontMask ? Qbold : Qmedium);
169   FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
170       traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
171   FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
172       traits & NSCondensedFontMask ? Qcondensed :
173         traits & NSExpandedFontMask ? Qexpanded : Qnormal);
175   ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
176   ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
177   ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
179   if (NSFONT_TRACE)
180     {
181       fprintf (stderr, "created font_entity:\n    ");
182       debug_print (font_entity);
183      }
185   [suffix release];
186   return font_entity;
190 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
191 static int
192 nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
194   int i, d =0;
195   for (i =0; i<sizeof (unsigned int)*8; i++)
196     {
197       d += (traits1 & 0x1) ^ (traits2 & 0x1);
198       traits1 >> 1;
199       traits2 >> 1;
200     }
201   return d;
205 /* Default font entity based on Monaco. */
206 static Lisp_Object
207 nsfont_fallback_entity ()
209   NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
210   NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
211                                     [NSNumber numberWithUnsignedInt: 5],
212                                     [NSNumber numberWithUnsignedInt: 0], nil];
213   return nsfont_fmember_to_entity (family, famMemberSpec);
217 /* ==========================================================================
219     Font driver implementation
221    ========================================================================== */
223 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
224 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
225 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
226 static Lisp_Object nsfont_list_family (Lisp_Object frame);
227 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
228                                  int pixel_size);
229 static void nsfont_close (FRAME_PTR f, struct font *font);
230 static int nsfont_has_char (Lisp_Object entity, int c);
231 static unsigned int nsfont_encode_char (struct font *font, int c);
232 static int nsfont_text_extents (struct font *font, unsigned int *code,
233                                 int nglyphs, struct font_metrics *metrics);
234 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
235                         int with_background);
237 struct font_driver nsfont_driver =
238   {
239     (Lisp_Object) NULL,         /* Qns */
240     1,                          /* case sensitive */
241     nsfont_get_cache,
242     nsfont_list,
243     nsfont_match,
244     nsfont_list_family,
245     NULL,                       /*free_entity */
246     nsfont_open,
247     nsfont_close,
248     NULL,                       /* prepare_face */
249     NULL,                       /* done_face */
250     nsfont_has_char,
251     nsfont_encode_char,
252     nsfont_text_extents,
253     nsfont_draw,
254     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
255                  anchor_point, otf_capability, otf_driver,
256                  start_for_frame, end_for_frame, shape */
257   };
260 /* Return a cache of font-entities on FRAME.  The cache must be a
261    cons whose cdr part is the actual cache area.  */
262 static Lisp_Object
263 nsfont_get_cache (FRAME_PTR frame)
265   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
266   return (dpyinfo->name_list_element);
270 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value
271    is a vector of font-entities.  This is the sole API that
272    allocates font-entities.  */
273 static Lisp_Object
274 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
276   Lisp_Object list = Qnil;
277   Lisp_Object tem;
278   NSString *family;
279   NSArray *families;
280   NSEnumerator *famEnum;
281   NSFontManager *fontMgr;
282   unsigned int traits = nsfont_spec_to_traits (font_spec);
284   if (NSFONT_TRACE)
285     {
286       fprintf (stderr, "nsfont: list for fontspec:\n    ");
287       debug_print (font_spec);
288     }
290   /* if has non-unicode registry, give up */
291   tem = AREF (font_spec, FONT_REGISTRY_INDEX);
292   if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
293     return Qnil;
295   fontMgr = [NSFontManager sharedFontManager];
297   family = nsfont_get_family (font_spec);
299   if (family != nil)
300     families = [NSArray arrayWithObject: family];
301   else
302     families = [fontMgr availableFontFamilies];
304   for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
305     {
306       NSEnumerator *fm;
307       NSArray *fmember, *firstMember = nil;
308       unsigned int mtraits;
309       BOOL foundItal = NO || (traits & NSUnitalicFontMask);
310       NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
311 #ifdef NS_IMPL_COCOA
312       /* LastResort is special: not a family but a font name only */
313       if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
314         {
315           famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
316               @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
317               [NSNumber numberWithUnsignedInt: 0], nil]];
318         }
319 #endif
321       /* fmember = [postscriptName style weight traits] */
322       fm  = [famMembers objectEnumerator];
323       while (fmember = [fm nextObject])
324         {
325           mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
326           if ((mtraits & traits) == traits)
327             {
328               list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
329               if (mtraits & NSItalicFontMask)
330                 foundItal = YES;
331               if (firstMember == nil)
332                 firstMember = fmember;
333             }
334         }
335       if (foundItal == NO && firstMember != nil)
336         {
337           /* no italic member found; add a synthesized one */
338           NSMutableArray *smember = [firstMember mutableCopy];
339           [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
340           mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
341           mtraits |= NSItalicFontMask;
342           [smember replaceObjectAtIndex: 3
343                    withObject: [NSNumber numberWithUnsignedInt: mtraits]];
344 /*NSLog (@"-- adding synthItal member: %@", smember); */
345           list = Fcons (nsfont_fmember_to_entity (family, smember), list);
346           [smember release];
347         }
348     }
350   if (NSFONT_TRACE)
351       fprintf (stderr, "    Returning %d entities.\n", XINT (Flength (list)));
353   return (NILP (list) ? Qnil : Fvconcat (1, &list));/* Qnil was null_vector */
357 /* Return a font entity most closely maching with FONT_SPEC on
358    FRAME.  The closeness is determined by the font backend, thus
359    `face-font-selection-order' is ignored here.  */
360 static Lisp_Object
361 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
363   long traits = nsfont_spec_to_traits (font_spec);
364   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
365   NSString *family;
366   Lisp_Object tem;
368   if (NSFONT_TRACE)
369     {
370       fprintf (stderr, "nsfont: match for fontspec:\n    ");
371       debug_print (font_spec);
372     }
374   /* if has non-unicode registry, just return fallback */
375 #if 0
376   tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
377   if (!NILP (tem))
378     fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
379 #endif
380   tem = AREF (font_spec, FONT_REGISTRY_INDEX);
381   if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
382     return nsfont_fallback_entity ();
384   family = nsfont_get_family (font_spec);
386   if (family != nil)
387     {
388       /* try to find close font in family */
389       NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
390       NSEnumerator *fm = [famMembers objectEnumerator];
391       NSArray *fmember;
392       int minDist = sizeof (unsigned int) * 8 + 1;
393       int bestMatchIdx = -1;
394       int i;
396       for (i =0; fmember = [fm nextObject]; i++)
397         {
398           unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
399           int dist = nsfont_trait_distance ((mtraits & traits), traits);
400           if (dist < minDist)
401             {
402               bestMatchIdx = i;
403               minDist = dist;
404             }
405         }
406       if (bestMatchIdx != -1)
407         return nsfont_fmember_to_entity
408           (family, [famMembers objectAtIndex: bestMatchIdx]);
409     }
411   /* no family that had members was given; find any font matching traits */
412   {
413     NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
414     if (fontNames && [fontNames count]  > 0)
415       {
416         NSString *fontName = [fontNames objectAtIndex: 0];
417         /*PENDING: is there a more efficient way to get family name? */
418         NSFont *font = [NSFont fontWithName: fontName size: 0];
419         if (font != nil)
420           {
421             /* now need to get suffix part of name.. */
422             NSString *family = [font familyName];
423             NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
424                                  objectEnumerator];
425             NSArray *fmember;
426             while (fmember = [fm nextObject])
427               {
428                 unsigned int mtraits =
429                   [[fmember objectAtIndex: 3] unsignedIntValue];
430                 if (mtraits & traits == traits)
431                   return nsfont_fmember_to_entity (family, fmember);
432               }
433           }
434       }
435   }
437   /* if we get here, return the fallback */
438   if (NSFONT_TRACE)
439       fprintf (stderr, "    *** returning fallback\n");
441   return nsfont_fallback_entity ();
445 /* List available families.  The value is a list of family names
446    (symbols). */
447 static Lisp_Object
448 nsfont_list_family (Lisp_Object frame)
450   Lisp_Object list = Qnil;
451   NSEnumerator *families =
452     [[[NSFontManager sharedFontManager] availableFontFamilies]
453       objectEnumerator];
454   NSString *family;
455   while (family = [families nextObject])
456       list = Fcons (intern ([family UTF8String]), list);
457   /*PENDING: escape the name? */
459   if (NSFONT_TRACE)
460     fprintf (stderr, "nsfont: list families returning %d entries\n",
461             XINT (Flength (list)));
463   return list;
467 /* utility: get width of a char c in screen font sfont */
468 static float
469 nsfont_char_width (NSFont *sfont, int c)
471   float w;
472   NSString *cstr = [NSString stringWithFormat: @"%c", c];
473 #ifdef NS_IMPL_COCOA
474   NSGlyph glyph = [sfont glyphWithName: cstr];
475   if (glyph)
476     {
477       float w = [sfont advancementForGlyph: glyph].width;
478       if (w >= 1.5)
479         return w;
480     }
481 #endif
482   w = [sfont widthOfString: cstr];
483   return max (w, 2.0);
487 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
488    scalable, open it with PIXEL_SIZE.  */
489 static Lisp_Object
490 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
492   BOOL synthItal;
493   struct nsfont_info *font_info;
494   struct font *font;
495   unsigned int traits = nsfont_spec_to_traits (font_entity);
496   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
497   NSString *family;
498   NSFont *nsfont, *sfont;
499   Lisp_Object tem;
500   NSRect brect;
501   Lisp_Object font_object;
502   int i;
503   int fixLeopardBug;
504 #if 0
505   static NSMutableDictionary *fontCache = nil;
507   /* 2008/03/08: The same font may end up being requested for different
508      entities, due to small differences in numeric values or other issues,
509      or for different copies of the same entity.  Therefore we cache to
510      avoid creating multiple struct font objects (with metrics cache, etc.)
511      for the same NSFont object.
512      2008/06/01: This is still an issue, but after font backend refactoring
513      caching will be more difficult, needs to be reworked before enabling. */
514   if (fontCache == nil)
515     fontCache = [[NSMutableDictionary alloc] init];
516 #endif
518   font_object = font_make_object (VECSIZE (struct nsfont_info), font_entity,
519                                   pixel_size);
520   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
521   font = (struct font *)font_info;
522   if (!font)
523     return NULL; /*PENDING: this copies w32, but causes a segfault */
525   if (NSFONT_TRACE)
526     {
527       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
528       debug_print (font_entity);
529     }
531   if (pixel_size <= 0)
532     {
533       /* try to get it out of frame params */
534         Lisp_Object tem = get_frame_param (f, Qfontsize);
535         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
536     }
538   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
539   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
540                                        9);
541   family = nsfont_get_family (font_entity);
542   if (NSFONT_TRACE)
543     {
544       fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\n",
545                [family UTF8String], traits, traits & NSBoldFontMask);
546     }
548   /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
549   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
550   nsfont = [fontMgr fontWithFamily: family
551                             traits: traits weight: fixLeopardBug
552                               size: pixel_size];
553   /* if didn't find, try synthetic italic */
554   if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
555     {
556       nsfont = [fontMgr fontWithFamily: family
557                                 traits: traits & ~NSItalicFontMask
558                                 weight: fixLeopardBug size: pixel_size];
559     }
560 #ifdef NS_IMPL_COCOA
561   /* LastResort not really a family */
562   if (nsfont == nil && [@"LastResort" isEqualToString: family])
563     {
564       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
565     }
566 #endif
568   if (nsfont == nil)
569     {
570       message_with_string ("*** Warning: font in family '%s' not found",
571                           build_string ([family UTF8String]), 1);
572       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
573       if (!nsfont)
574         {
575           fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
576           return NULL;
577         }
578     }
580 #if 0
581   {
582     NSNumber *cached = [fontCache objectForKey: nsfont];
583     if (cached != nil && !synthItal)
584       {
585 fprintf (stderr, "*** CACHE HIT!\n");
586         struct font_info *existing =
587           (struct nsfont_info *)[cached unsignedLongValue];
588         /* ... */
589       }
590     else
591       {
592         if (!synthItal)
593           [fontCache
594             setObject: [NSNumber numberWithUnsignedLong:
595                                    (unsigned long)font_info]
596                forKey: nsfont];
597       }
598   }
599 #endif
601   font_info->glyphs = (unsigned short *)
602     xmalloc (0x100 * sizeof (unsigned short *));
603   font_info->metrics = (struct font_metrics *)
604     xmalloc (0x100 * sizeof (struct font_metrics *));
605   if (!font_info->glyphs || !font_info->metrics)
606     return NULL;
607   bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
608   bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
611 BLOCK_INPUT;
613   /* for metrics */
614   sfont = [nsfont screenFont];
615   if (sfont == nil)
616     sfont = nsfont;
618   /* non-metric backend font struct fields */
619   font = (struct font *) font_info;
620   font->pixel_size = [sfont pointSize];
621   font->driver = &nsfont_driver;
622   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
623   font->encoding_charset = -1;
624   font->repertory_charset = -1;
625   font->default_ascent = 0;
626   font->vertical_centering = 0;
627   font->baseline_offset = 0;
628   font->relative_compose = 0;
629   font->font_encoder = NULL;
631   /*PENDING: does anything care about this? */
632   font->props[FONT_FORMAT_INDEX] = Qns;
633   font->props[FONT_FILE_INDEX] = Qnil;
635   {
636     double expand, shrink, hshrink;
637     float full_height, min_height, hd;
638     const char *fontName = [[nsfont fontName] UTF8String];
639     int len = strlen (fontName);
641 #ifdef NS_IMPL_GNUSTEP
642     font_info->nsfont = sfont;
643 #else
644     font_info->nsfont = nsfont;
645 #endif
646     [font_info->nsfont retain];
648     /* set up ns_font (defined in nsgui.h) */
649     font_info->name = (char *)xmalloc (strlen (fontName)+1);
650     bcopy (fontName, font_info->name, strlen (fontName)+1);
651     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
652     font_info->ital =
653       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
655     /* Metrics etc.; some fonts return an unusually large max advance, so we
656        only use it for fonts that have wide characters. */
657     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
658       [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
660     brect =  [sfont boundingRectForFont];
661     full_height = brect.size.height;
662     min_height = [sfont ascender] - [sfont descender];
663     hd = full_height - min_height;
665     if (!NUMBERP (ns_expand_space))
666       error ("No expand space defined");
668     /* ns_expand_space = 0.0 is use standard height; less shrink, more expand */
669     expand = XFLOATINT (ns_expand_space) + 0.5;
671     if (expand < 0.0)
672       {
673         shrink = 1 + expand;
674         hshrink = 1 + expand / 2.0;
675         expand = 0.0;
676       }
677     else
678       shrink = hshrink = 1.0;
680     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
681     font_info->underwidth = [sfont underlineThickness];
682     font_info->size = font->pixel_size;
683     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
685     /* max bounds */
686     font_info->max_bounds.ascent =
687       lrint (hshrink * [sfont ascender] + expand * hd/2);
688     font_info->max_bounds.descent =
689       -lrint (hshrink* [sfont descender] - expand*hd/2);
690     font_info->height =
691       font_info->max_bounds.ascent + font_info->max_bounds.descent;
692     font_info->max_bounds.width = lrint (font_info->width);
693     font_info->max_bounds.lbearing = lrint (brect.origin.x);
694     font_info->max_bounds.rbearing =
695       lrint (brect.size.width - font_info->width);
696       /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
698 #ifdef NS_IMPL_COCOA
699     /* set up synthItal and the CG font */
700     font_info->synthItal = synthItal;
701     {
702       ATSFontRef atsFont = ATSFontFindFromPostScriptName
703         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
705       if (atsFont == kATSFontRefUnspecified)
706         {
707           /* see if we can get it by dropping italic (then synthesizing) */
708           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
709               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
710                 fontName], kATSOptionFlagsDefault);
711           if (atsFont != kATSFontRefUnspecified)
712               font_info->synthItal = YES;
713           else
714             {
715               /* last resort fallback */
716               atsFont = ATSFontFindFromPostScriptName
717                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
718             }
719         }
720       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
721     }
722 #endif
724     /* set up metrics portion of font struct */
725     font->ascent = [sfont ascender];
726     font->descent = -[sfont descender];
727     font->min_width = [sfont widthOfString: @"|"]; /* PENDING */
728     font->space_width = lrint (nsfont_char_width (sfont, ' '));
729     font->average_width = lrint (font_info->width);
730     font->max_width = lrint (font_info->max_bounds.width);
731     font->height = lrint (font_info->height);
732     font->underline_position = lrint (font_info->underpos);
733     font->underline_thickness = lrint (font_info->underwidth);
735     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
736     font->props[FONT_FULLNAME_INDEX] =
737       make_unibyte_string (font_info->name, strlen (font_info->name));
738   }
739   UNBLOCK_INPUT;
741   return font_object;
745 /* Close FONT on frame F. */
746 static void
747 nsfont_close (FRAME_PTR f, struct font *font)
749   struct nsfont_info *font_info = (struct nsfont_info *)font;
750   int i;
752   /* PENDING: this occurs apparently due to same failure to detect same font
753      that causes need for cache in nsfont_open ()
754      (came after unicode-2 -> trunk) */
755   if (!font_info)
756       return;
758   for (i =0; i<0x100; i++)
759     {
760       if (font_info->glyphs[i])
761         xfree (font_info->glyphs[i]);
762       if (font_info->metrics[i])
763         xfree (font_info->metrics[i]);
764     }
765   [font_info->nsfont release];
766 #ifdef NS_IMPL_COCOA
767       CGFontRelease (font_info->cgfont);
768 #endif
769       xfree (font_info->name);
770       xfree (font_info);
774 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
775    return 1.  If not, return 0.  If a font must be opened to check
776    it, return -1. */
777 static int
778 nsfont_has_char (Lisp_Object entity, int c)
780   return -1;
784 /* Return a glyph code of FONT for character C (Unicode code point).
785    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
786 static unsigned int
787 nsfont_encode_char (struct font *font, int c)
789   struct nsfont_info *font_info = (struct nsfont_info *)font;
790   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
791   unsigned short g;
793   if (c > 0xFFFF)
794     return FONT_INVALID_CODE;
796   /* did we already cache this block? */
797   if (!font_info->glyphs[high])
798     ns_uni_to_glyphs (font_info, high);
800   g = font_info->glyphs[high][low];
801 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
802   return g == 0xFFFF ? FONT_INVALID_CODE : g;
806 /* Perform the size computation of glyphs of FONT and fill in members
807    of METRICS.  The glyphs are specified by their glyph codes in
808    CODE (length NGLYPHS). */
809 static int
810 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
811                      struct font_metrics *metrics)
813   struct nsfont_info *font_info = (struct nsfont_info *)font;
814   struct font_metrics *pcm;
815   unsigned char high, low;
816   int totalWidth = 0;
817   int i;
819   bzero (metrics, sizeof (struct font_metrics));
821   for (i =0; i<nglyphs; i++)
822     {
823       /* get metrics for this glyph, filling cache if need be */
824       /* PENDING: get metrics for whole string from an NSLayoutManager
825                  (if not too slow) */
826       high = (code[i] & 0xFF00) >> 8;
827       low = code[i] & 0x00FF;
828       if (!font_info->metrics[high])
829         ns_glyph_metrics (font_info, high);
830       pcm = &(font_info->metrics[high][low]);
832       if (metrics->lbearing > totalWidth + pcm->lbearing)
833         metrics->lbearing = totalWidth + pcm->lbearing;
834       if (metrics->rbearing < totalWidth + pcm->rbearing)
835         metrics->rbearing = totalWidth + pcm->rbearing;
836       if (metrics->ascent < pcm->ascent)
837         metrics->ascent = pcm->ascent;
838       if (metrics->descent < pcm->descent)
839         metrics->descent = pcm->descent;
841       totalWidth += pcm->width;
842     }
844   metrics->width = totalWidth;
846   return totalWidth; /* not specified in doc, but xfont.c does it */
850 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
851    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
852    is nonzero, fill the background in advance.  It is assured that
853    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
854 static int
855 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
856              int with_background)
857 /* NOTE: focus and clip must be set
858      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
860   static char cbuf[1024];
861   char *c = cbuf;
862 #ifdef NS_IMPL_GNUSTEP
863   static float advances[1024];
864   float *adv = advances;
865 #else
866   static CGSize advances[1024];
867   CGSize *adv = advances;
868 #endif
869   struct face *face;
870   NSRect r;
871   struct nsfont_info *font = ns_tmp_font;
872   NSColor *col, *bgCol;
873   unsigned short *t = s->char2b;
874   int i, len;
876   /* Select face based on input flags */
877   switch (ns_tmp_flags)
878     {
879     case NS_DUMPGLYPH_CURSOR:
880       face = s->face;
881       break;
882     case NS_DUMPGLYPH_MOUSEFACE:
883       face = FACE_FROM_ID (s->f,
884                            FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
885       if (!face)
886         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
887       break;
888     default:
889       face = s->face;
890     }
892   r.origin.x = s->x;
893   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
894     r.origin.x += abs (s->face->box_line_width);
896   r.origin.y = s->y;
897   r.size.height = FONT_HEIGHT (font);
899   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
900      NS to render the string, it will come out differently from the individual
901      character widths added up because of layout processing. */
902   {
903     XCharStruct *cs;
904     int cwidth, twidth = 0;
905     int hi, lo;
906     char isComposite = 0; /* s->first_glyph->type == COMPOSITE_GLYPH; */
907     /* PENDING: composition: no vertical displacement is considered. */
908     t+= s->gidx; /* advance into composition */
909     for (i =0; i<s->nchars - s->gidx; i++, t++)
910       {
911         hi = (*t & 0xFF00) >> 8;
912         lo = *t & 0x00FF;
913         if (isComposite)
914           {
915             cwidth = s->cmp->offsets[s->gidx++ * 2] - twidth;
916           }
917         else
918           {
919             if (!font->metrics[hi]) /*PENDING: why/how can we need this now? */
920               ns_glyph_metrics (font, hi);
921             cwidth = font->metrics[hi][lo].width;
922           }
923         twidth += cwidth;
924 #ifdef NS_IMPL_GNUSTEP
925         *adv++ = cwidth;
926         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
927 #else
928         (*adv++).width = cwidth;
929 #endif
930       }
931     len = adv - advances;
932     r.size.width = twidth;
933     *c = 0;
934   }
936   /* fill background if requested */
937   if (with_background)
938     {
939       NSRect br = r;
940       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
941       int mbox_line_width = max (s->face->box_line_width, 0);
943       if (s->row->full_width_p)
944         {
945           if (br.origin.x <= fibw + 1 + mbox_line_width)
946             {
947               br.size.width += br.origin.x - mbox_line_width;
948               br.origin.x = mbox_line_width;
949             }
950           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
951                 <= fibw+1)
952             br.size.width += fibw;
953         }
954       if (s->face->box == FACE_NO_BOX)
955         {
956           /* expand unboxed top row over internal border */
957           if (br.origin.y <= fibw + 1 + mbox_line_width)
958             {
959               br.size.height += br.origin.y;
960               br.origin.y = 0;
961             }
962         }
963       else
964         {
965           int correction = abs (s->face->box_line_width)+1;
966           br.origin.y += correction;
967           br.size.height -= 2*correction;
968           br.origin.x += correction;
969           br.size.width -= 2*correction;
970         }
972       if (!s->face->stipple)
973         [(NS_FACE_BACKGROUND (face) != nil
974           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
975           : FRAME_BACKGROUND_COLOR (s->f)) set];
976       else
977         {
978           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
979           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
980         }
981       NSRectFill (br);
982     }
985   /* set up for character rendering */
986   r.origin.y += font->voffset + (s->height - font->height)/2;
988   col = (NS_FACE_FOREGROUND (face) != nil
989          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
990          : FRAME_FOREGROUND_COLOR (s->f));
991   /*PENDING: find another way to pass this */
992   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
993            : (NS_FACE_BACKGROUND (face) != nil
994               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
995               : FRAME_BACKGROUND_COLOR (s->f)));
997   /* render under GNUstep using DPS */
998 #ifdef NS_IMPL_GNUSTEP
999   {
1000     NSGraphicsContext *context = GSCurrentContext ();
1002     DPSgsave (context);
1003     [font->nsfont set];
1005     /* do erase if "foreground" mode */
1006     if (bgCol != nil)
1007       {
1008         [bgCol set];
1009         DPSmoveto (context, r.origin.x, r.origin.y);
1010 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1011         DPSxshow (context, cbuf, advances, len);
1012         DPSstroke (context);
1013         [col set];
1014 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1015       }
1017     /* do underline */
1018     if (face->underline_p)
1019       {
1020         if (face->underline_color != nil)
1021           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1022         else
1023           [col set];
1024         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1025         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1026         if (face->underline_color != nil)
1027           [col set];
1028       }
1029     else
1030       [col set];
1032     /* draw with DPSxshow () */
1033     DPSmoveto (context, r.origin.x, r.origin.y);
1034     DPSxshow (context, cbuf, advances, len);
1035     DPSstroke (context);
1037     DPSgrestore (context);
1038     return to-from;
1039   }
1041 #else  /* NS_IMPL_COCOA */
1042   {
1043     CGContextRef gcontext =
1044       [[NSGraphicsContext currentContext] graphicsPort];
1045     static CGAffineTransform fliptf;
1046     static BOOL firstTime = YES;
1048     if (firstTime)
1049       {
1050         firstTime = NO;
1051         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1052       }
1054     CGContextSaveGState (gcontext);
1056     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1058     CGContextSetFont (gcontext, font->cgfont);
1059     CGContextSetFontSize (gcontext, font->size);
1060     if (ns_antialias_text == NO || font->size <= ns_antialias_threshold)
1061       CGContextSetShouldAntialias (gcontext, 0);
1062     else
1063       CGContextSetShouldAntialias (gcontext, 1);
1064     if (ns_use_qd_smoothing)
1065       CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1067     CGContextSetTextMatrix (gcontext, fliptf);
1069     if (bgCol != nil)
1070       {
1071         /* foreground drawing; erase first to avoid overstrike */
1072         [bgCol set];
1073         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1074         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1075         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1076         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1077       }
1079     if (face->underline_p)
1080       {
1081         if (face->underline_color != nil)
1082           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1083         else
1084           [col set];
1085         CGContextBeginPath (gcontext);
1086         CGContextMoveToPoint (gcontext,
1087                               r.origin.x, r.origin.y + font->underpos);
1088         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1089                                 r.origin.y + font->underpos);
1090         CGContextStrokePath (gcontext);
1091         if (face->underline_color != nil)
1092           [col set];
1093       }
1094     else
1095       [col set];
1097     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1098     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->gidx,
1099                                     advances, len);
1101     if (face->overstrike)
1102       {
1103         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1104         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->gidx,
1105                                         advances, len);
1106       }
1108     CGContextRestoreGState (gcontext);
1109     return;
1110   }
1111 #endif  /* NS_IMPL_COCOA */
1116 /*  Auto-creates a fontset built around the font in font_object,
1117     by creating an attributed string with characters from each
1118     script, then requesting the NS text system to fix attributes
1119     in range. */
1120 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1122   Lisp_Object script, famAndReg;
1123   struct nsfont_info *font_info =
1124     (struct nsfont_info *)XFONT_OBJECT (font_object);
1126   /* NS text system (and char buf) init */
1127   static NSTextStorage *store;
1128   static NSLayoutManager *layout;
1129   static NSRange range;
1130   static NSMutableDictionary *attribs;
1131   static Lisp_Object *scripts;
1132   static int nscripts;
1133   static int *scriptsNchars;
1134   static BOOL firstTime = YES;
1135   Lisp_Object regString = build_string ("iso10646-1");
1136   int i, j;
1138   if (firstTime == YES)
1139     {
1140       nscripts = XINT (Flength (Vscript_representative_chars));
1141       scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1142       unsigned char *buf = malloc (4*nscripts*sizeof (char));
1143       Lisp_Object scriptsChars = Vscript_representative_chars;
1144       unsigned char *tpos = buf;
1146       scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1148       for (i =0; i<nscripts; i++)
1149         {
1150           Lisp_Object sChars = XCAR (scriptsChars);
1151           Lisp_Object chars = XCDR (sChars);
1152           unsigned int ch, c =0;
1153           scripts[i] = XCAR (sChars);
1155           while (CONSP (chars))
1156             {
1157               ch = XUINT (XCAR (chars));
1158               chars = XCDR (chars);
1159               CHAR_STRING_ADVANCE (ch, tpos);
1160               c++;
1161             }
1162           scriptsNchars[i] = c;
1164           scriptsChars = XCDR (scriptsChars);
1165         }
1166       *tpos = '\0';
1168       store = [[NSTextStorage alloc] init];
1169       layout = [[NSLayoutManager alloc] init];
1170       [store addLayoutManager: layout];
1171       [layout release];
1173       [store beginEditing];
1174       [[store mutableString] appendString:
1175                                [NSString stringWithUTF8String: buf]];
1176       [store endEditing];
1178       free (buf);
1179       range = NSMakeRange (0, [store length]);
1181       attribs = [[NSMutableDictionary alloc] init];
1182       firstTime = NO;
1183     }
1185   /* set the fonts */
1186   [store beginEditing];
1187   [store removeAttribute: NSFontAttributeName range: range];
1188   [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1189   [store addAttributes: attribs range: range];
1190   [store endEditing];
1192   /* read them out */
1193   {
1194     NSMutableDictionary *map =
1195       [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1196     NSEnumerator *fonts;
1197     NSFont *cfont = nil, *tfont;
1198     NSNumber *n;
1199     int idx = 0;
1200     int max;
1201     for (i =0; i<nscripts; i++)
1202       {
1203         [map removeAllObjects];
1204         for (j =0; j<scriptsNchars[i]; j++)
1205           {
1206             cfont = [store attribute: NSFontAttributeName atIndex: idx++
1207                       effectiveRange: NULL];
1208             n = [map objectForKey: cfont];
1209             if (n == nil)
1210               n = [NSNumber numberWithInt: 1];
1211             else
1212               n = [NSNumber numberWithInt: [n intValue] + 1];
1213             [map setObject: n forKey: cfont];
1214           }
1216         /* majority rules */
1217         max = 0;
1218         fonts = [map keyEnumerator];
1219         while (tfont = [fonts nextObject])
1220           {
1221             n = [map objectForKey: tfont];
1222             if ([n intValue] > max)
1223               {
1224                 cfont = tfont;
1225                 max = [n intValue];
1226               }
1227           }
1229         if (cfont != nil)
1230           {
1231             char *family = [[cfont familyName] UTF8String];
1232             Lisp_Object famAndReg;
1234             nsfont_escape_name (family);
1235             famAndReg = Fcons (build_string (family), regString);
1237             if (NSFONT_TRACE)
1238               fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1239                       font_info->name, family,
1240                        SDATA (SYMBOL_NAME (scripts[i])));
1242             Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
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         /*PENDING: 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
1498    (do not change this comment) */