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