]> code.delx.au - gnu-emacs/blobdiff - src/nsfont.m
Merge from emacs-24; up to 2012-12-01T13:25:13Z!cyd@gnu.org
[gnu-emacs] / src / nsfont.m
index aaec130b01d3faaa4bfcf9e9597e251ebf67e593..2ba38b7570ef432de13914ace85cf909b8ba67b4 100644 (file)
@@ -1,6 +1,6 @@
 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
    See font.h
-   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2006-2012 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -22,8 +22,7 @@ Author: Adrian Robert (arobert@cogsci.ucsd.edu)
 
 /* This should be the first include, as it may set up #defines affecting
    interpretation of even the system includes. */
-#include "config.h"
-#include <setjmp.h>
+#include <config.h>
 
 #include "lisp.h"
 #include "dispextern.h"
@@ -37,6 +36,7 @@ Author: Adrian Robert (arobert@cogsci.ucsd.edu)
 #include "frame.h"
 #include "character.h"
 #include "font.h"
+#include "termchar.h"
 
 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
 #ifdef NS_IMPL_GNUSTEP
@@ -46,15 +46,15 @@ Author: Adrian Robert (arobert@cogsci.ucsd.edu)
 #define NSFONT_TRACE 0
 
 extern Lisp_Object Qns;
-extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
-static Lisp_Object Vns_reg_to_script;
+extern Lisp_Object Qnormal, Qbold, Qitalic;
 static Lisp_Object Qapple, Qroman, Qmedium;
+static Lisp_Object Qcondensed, Qexpanded;
 extern Lisp_Object Qappend;
-extern Lisp_Object ns_antialias_text;
 extern float ns_antialias_threshold;
 extern int ns_tmp_flags;
 extern struct nsfont_info *ns_tmp_font;
 
+
 /* font glyph and metrics caching functions, implemented at end */
 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
                               unsigned char block);
@@ -101,11 +101,11 @@ ns_get_family (Lisp_Object font_spec)
       return nil;
   else
     {
-      char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
+      char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
       NSString *family;
       ns_unescape_name (tmp);
       family = [NSString stringWithUTF8String: tmp];
-      free (tmp);
+      xfree (tmp);
       return family;
     }
 }
@@ -127,8 +127,8 @@ ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
    to NSFont descriptor.  Information under extra only needed for matching. */
 #define STYLE_REF 100
-static NSFontDescriptor
-*ns_spec_to_descriptor(Lisp_Object font_spec)
+static NSFontDescriptor *
+ns_spec_to_descriptor (Lisp_Object font_spec)
 {
     NSFontDescriptor *fdesc;
     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
@@ -154,14 +154,21 @@ static NSFontDescriptor
 
     fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
     if (family != nil)
+      {
        fdesc = [fdesc fontDescriptorWithFamily: family];
+      }
+
+    [fdAttrs release];
+    [tdict release];
     return fdesc;
 }
 
 
 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
 static Lisp_Object
-ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
+ns_descriptor_to_entity (NSFontDescriptor *desc,
+                         Lisp_Object extra,
+                         const char *style)
 {
     Lisp_Object font_entity = font_make_entity ();
     /*   NSString *psName = [desc postscriptName]; */
@@ -175,7 +182,7 @@ ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
     if (family == nil)
       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
 
-    escapedFamily = strdup ([family UTF8String]);
+    escapedFamily = xstrdup ([family UTF8String]);
     ns_escape_name (escapedFamily);
 
     ASET (font_entity, FONT_TYPE_INDEX, Qns);
@@ -195,8 +202,8 @@ ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
                    make_number (100 + 100
                         * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
-                   traits & NSFontCondensedTrait ? Qcondensed :
-                   traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
+                    traits & NSFontCondensedTrait ? Qcondensed :
+                    traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
                    make_number (100 + 100
                         * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
@@ -216,46 +223,82 @@ ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
        debug_print (font_entity);
       }
 
-    free (escapedFamily);
+    xfree (escapedFamily);
     return font_entity;
 }
 
 
 /* Default font entity. */
 static Lisp_Object
-ns_fallback_entity ()
+ns_fallback_entity (void)
 {
   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
       fontDescriptor], Qnil, NULL);
 }
 
 
-/* Utility: get width of a char c in screen font sfont */
+/* Utility: get width of a char c in screen font SFONT */
 static float
 ns_char_width (NSFont *sfont, int c)
 {
-    float w;
-    NSString *cstr = [NSString stringWithFormat: @"%c", c];
+  float w = -1.0;
+  NSString *cstr = [NSString stringWithFormat: @"%c", c];
+
 #ifdef NS_IMPL_COCOA
-    NSGlyph glyph = [sfont glyphWithName: cstr];
-    if (glyph)
-      {
-       float w = [sfont advancementForGlyph: glyph].width;
-       if (w >= 1.5)
-           return w;
-      }
+  NSGlyph glyph = [sfont glyphWithName: cstr];
+  if (glyph)
+    w = [sfont advancementForGlyph: glyph].width;
 #endif
+
+  if (w < 0.0)
     {
       NSDictionary *attrsDictionary =
         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
       w = [cstr sizeWithAttributes: attrsDictionary].width;
     }
-    return max (w, 2.0);
+
+  return max (w, 1.0);
+}
+
+/* Return average width over ASCII printable characters for SFONT.  */
+
+static NSString *ascii_printable;
+
+static int
+ns_ascii_average_width (NSFont *sfont)
+{
+  float w = -1.0;
+
+  if (!ascii_printable)
+    {
+      char chars[96];
+      int ch;
+      for (ch = 0; ch < 95; ch++)
+       chars[ch] = ' ' + ch;
+      chars[95] = '\0';
+
+      ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
+    }
+
+#ifdef NS_IMPL_COCOA
+  NSGlyph glyph = [sfont glyphWithName: ascii_printable];
+  if (glyph)
+    w = [sfont advancementForGlyph: glyph].width;
+#endif
+
+  if (w < 0.0)
+    {
+      NSDictionary *attrsDictionary =
+       [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
+      w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
+    }
+
+  return lrint (w / 95.0);
 }
 
 
 /* Return whether set1 covers set2 to a reasonable extent given by pct.
-   We check, out of each 16 unicode char range containing chars in set2,
+   We check, out of each 16 Unicode char range containing chars in set2,
    whether at least one character is present in set1.
    This must be true for pct of the pairs to consider it covering. */
 static BOOL
@@ -265,6 +308,11 @@ ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
     int i, off = 0, tot = 0;
 
+    /* Work around what appears to be a GNUstep bug.
+       See <http://bugs.gnu.org/11853>.  */
+    if (! (bytes1 && bytes2))
+      return NO;
+
     for (i=0; i<4096; i++, bytes1++, bytes2++)
        if (*bytes2)
          {
@@ -282,13 +330,13 @@ ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
 static NSString
 *ns_lang_to_script (Lisp_Object lang)
 {
-    if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
+    if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
        return @"han";
     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
              have more characters. */
-    else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
+    else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
        return @"han";
-    else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
+    else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
        return @"hangul";
     else
        return @"";
@@ -296,13 +344,13 @@ static NSString
 
 
 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
-   everyone just use some standard unicode names for these?) */
+   everyone just use some standard Unicode names for these?) */
 static NSString
 *ns_otf_to_script (Lisp_Object otf)
 {
     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
     return CONSP (script)
-       ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
+       ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
        : @"";
 }
 
@@ -315,10 +363,10 @@ static NSString
     while CONSP (rts)
       {
         r = XCAR (XCAR (rts));
-        if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
+        if (!strncmp(SSDATA(r), reg, strlen(SSDATA(r))))
           {
             script = XCDR (XCAR (rts));
-            return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
+            return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
           }
         rts = XCDR (rts);
       }
@@ -328,7 +376,7 @@ static NSString
 
 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
    plus registry regular property, for something that can be mapped to a
-   unicode script.  Empty string returned if no script spec found. */
+   Unicode script.  Empty string returned if no script spec found. */
 static NSString
 *ns_get_req_script (Lisp_Object font_spec)
 {
@@ -344,7 +392,7 @@ static NSString
            Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
            if (EQ (key, QCscript) && SYMBOLP (val))
                return [NSString stringWithUTF8String:
-                           SDATA (SYMBOL_NAME (val))];
+                           SSDATA (SYMBOL_NAME (val))];
            if (EQ (key, QClang) && SYMBOLP (val))
                return ns_lang_to_script (val);
            if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
@@ -362,7 +410,7 @@ static NSString
         if (EQ (reg, Qiso10646_1))
           reg = Qiso8859_1;
 #endif
-        return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
+        return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
       }
 
     return @"";
@@ -384,7 +432,7 @@ accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
 }
 
 
-/* Use the unicode range information in Vchar_script_table to convert a script
+/* Use the Unicode range information in Vchar_script_table to convert a script
    name into an NSCharacterSet. */
 static NSCharacterSet
 *ns_script_to_charset (NSString *scriptName)
@@ -425,7 +473,7 @@ static NSCharacterSet
    If none are found, we reduce the percentage and try again, until 5%.
    This provides a font with at least some characters if such can be found.
    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
-   (b) need approximate match as fonts covering full unicode ranges are rare. */
+   (b) need approximate match as fonts covering full Unicode ranges are rare. */
 static NSSet
 *ns_get_covering_families (NSString *script, float pct)
 {
@@ -453,7 +501,7 @@ static NSSet
            while (1)
              {
                NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
-               while (family = [allFamiliesEnum nextObject])
+               while ((family = [allFamiliesEnum nextObject]))
                  {
                    NSCharacterSet *fset = [[fontMgr fontWithFamily: family
                         traits: 0 weight: 5 size: 12.0]        coveredCharacterSet];
@@ -468,6 +516,7 @@ static NSSet
                if ([families count] > 0 || pct < 0.05)
                    break;
              }
+            [charset release];
          }
 #ifdef NS_IMPL_COCOA
        if ([families count] == 0)
@@ -511,12 +560,16 @@ ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
     if (isMatch)
        [fkeys removeObject: NSFontFamilyAttribute];
 
-    matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
+    if ([fkeys count] > 0)
+      matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
+    else
+      matchingDescs = [NSMutableArray array];
+
     if (NSFONT_TRACE)
        NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
              [matchingDescs count]);
 
-    for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
+    for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
       {
        if (![cFamilies containsObject:
                 [desc objectForKey: NSFontFamilyAttribute]])
@@ -535,12 +588,14 @@ ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
     family = [fdesc objectForKey: NSFontFamilyAttribute];
     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
       {
-       NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
-           fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
-           fontDescriptorWithFamily: family];
+        NSFontDescriptor *s1 = [NSFontDescriptor new];
+        NSFontDescriptor *sDesc
+          = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
+              fontDescriptorWithFamily: family];
        list = Fcons (ns_descriptor_to_entity (sDesc,
                                         AREF (font_spec, FONT_EXTRA_INDEX),
                                         "synthItal"), list);
+        [s1 release];
       }
 
     /* Return something if was a match and nothing found. */
@@ -548,8 +603,8 @@ ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
       return ns_fallback_entity ();
 
     if (NSFONT_TRACE)
-       fprintf (stderr, "    Returning %ld entities.\n",
-                 (long) XINT (Flength (list)));
+       fprintf (stderr, "    Returning %"pI"d entities.\n",
+                 XINT (Flength (list)));
 
     return list;
 }
@@ -575,7 +630,7 @@ static unsigned int nsfont_encode_char (struct font *font, int c);
 static int nsfont_text_extents (struct font *font, unsigned int *code,
                                 int nglyphs, struct font_metrics *metrics);
 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
-                        int with_background);
+                        bool with_background);
 
 struct font_driver nsfont_driver =
   {
@@ -629,7 +684,7 @@ nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
 }
 
 
-/* Return a font entity most closely maching with FONT_SPEC on
+/* Return a font entity most closely matching with FONT_SPEC on
    FRAME.  The closeness is determined by the font backend, thus
    `face-font-selection-order' is ignored here.
    Properties to be considered are same as for list(). */
@@ -650,13 +705,13 @@ nsfont_list_family (Lisp_Object frame)
     [[[NSFontManager sharedFontManager] availableFontFamilies]
       objectEnumerator];
   NSString *family;
-  while (family = [families nextObject])
+  while ((family = [families nextObject]))
       list = Fcons (intern ([family UTF8String]), list);
   /* FIXME: escape the name? */
 
   if (NSFONT_TRACE)
-    fprintf (stderr, "nsfont: list families returning %ld entries\n",
-            (long) XINT (Flength (list)));
+    fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
+            XINT (Flength (list)));
 
   return list;
 }
@@ -678,18 +733,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
   Lisp_Object tem;
   NSRect brect;
   Lisp_Object font_object;
-  int i;
   int fixLeopardBug;
-  static NSMutableDictionary *fontCache = nil;
-  NSNumber *cached;
-
-  /* 2008/03/08: The same font may end up being requested for different
-     entities, due to small differences in numeric values or other issues,
-     or for different copies of the same entity.  Therefore we cache to
-     avoid creating multiple struct font objects (with metrics cache, etc.)
-     for the same NSFont object. */
-  if (fontCache == nil)
-    fontCache = [[NSMutableDictionary alloc] init];
 
   if (NSFONT_TRACE)
     {
@@ -705,7 +749,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
     }
 
   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
-  synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
+  synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
                                        9);
   family = ns_get_family (font_entity);
   if (family == nil)
@@ -745,44 +789,26 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
   if (NSFONT_TRACE)
     NSLog (@"%@\n", nsfont);
 
-  /* Check the cache */
-  cached = [fontCache objectForKey: nsfont];
-  if (cached != nil && !synthItal)
-    {
-      if (NSFONT_TRACE)
-        fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
-      /* FIXME: Cast from (unsigned long) to Lisp_Object. */
-      XHASH (font_object) = [cached unsignedLongValue];
-      return font_object;
-    }
-  else
-    {
-      font_object = font_make_object (VECSIZE (struct nsfont_info),
-                                      font_entity, pixel_size);
-      if (!synthItal)
-        [fontCache setObject: [NSNumber numberWithUnsignedLong:
-                                         (unsigned long) XHASH (font_object)]
-                     forKey: nsfont];
-    }
-
+  font_object = font_make_object (VECSIZE (struct nsfont_info),
+                                  font_entity, pixel_size);
   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
   font = (struct font *) font_info;
   if (!font)
     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
 
-  font_info->glyphs = (unsigned short **)
-    xmalloc (0x100 * sizeof (unsigned short *));
-  font_info->metrics = (struct font_metrics **)
-    xmalloc (0x100 * sizeof (struct font_metrics *));
-  if (!font_info->glyphs || !font_info->metrics)
-    return Qnil;
-  bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
-  bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
+  font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
+  font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
 
-  BLOCK_INPUT;
+  block_input ();
 
   /* for metrics */
+#ifdef NS_IMPL_COCOA
+  sfont = [nsfont screenFontWithRenderingMode:
+                    NSFontAntialiasedIntegerAdvancementsRenderingMode];
+#else
   sfont = [nsfont screenFont];
+#endif
+
   if (sfont == nil)
     sfont = nsfont;
 
@@ -790,7 +816,6 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
   font = (struct font *) font_info;
   font->pixel_size = [sfont pointSize];
   font->driver = &nsfont_driver;
-  font->encoding_type = FONT_ENCODING_NOT_DECIDED;
   font->encoding_charset = -1;
   font->repertory_charset = -1;
   font->default_ascent = 0;
@@ -803,10 +828,15 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
   font->props[FONT_FILE_INDEX] = Qnil;
 
   {
-    double expand, hshrink;
-    float full_height, min_height, hd;
     const char *fontName = [[nsfont fontName] UTF8String];
-    int len = strlen (fontName);
+
+    /* The values specified by fonts are not always exact. For
+     * example, a 6x8 font could specify that the descender is
+     * -2.00000405... (represented by 0xc000000220000000).  Without
+     * adjustment, the code below would round the descender to -3,
+     * resulting in a font that would be one pixel higher than
+     * intended. */
+    CGFloat adjusted_descender = [sfont descender] + 0.0001;
 
 #ifdef NS_IMPL_GNUSTEP
     font_info->nsfont = sfont;
@@ -816,8 +846,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
     [font_info->nsfont retain];
 
     /* set up ns_font (defined in nsgui.h) */
-    font_info->name = (char *)xmalloc (strlen (fontName) + 1);
-    bcopy (fontName, font_info->name, strlen (fontName) + 1);
+    font_info->name = xstrdup (fontName);
     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
     font_info->ital =
       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
@@ -828,26 +857,16 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
 
     brect =  [sfont boundingRectForFont];
-    full_height = brect.size.height;
-    min_height = [sfont ascender] - [sfont descender];
-    hd = full_height - min_height;
 
-    /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
-    expand = 0.0;
-    hshrink = 1.0;
-
-    font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
+    font_info->underpos = [sfont underlinePosition];
     font_info->underwidth = [sfont underlineThickness];
     font_info->size = font->pixel_size;
-    font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
 
     /* max bounds */
-    font_info->max_bounds.ascent =
-      lrint (hshrink * [sfont ascender] + expand * hd/2);
-    /* [sfont descender] is usually negative.  Use floor to avoid
+    font_info->max_bounds.ascent = lrint ([sfont ascender]);
+    /* Descender is usually negative.  Use floor to avoid
        clipping descenders. */
-    font_info->max_bounds.descent =
-      -lrint (floor(hshrink* [sfont descender] - expand*hd/2));
+    font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
     font_info->height =
       font_info->max_bounds.ascent + font_info->max_bounds.descent;
     font_info->max_bounds.width = lrint (font_info->width);
@@ -883,11 +902,12 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
 
     /* set up metrics portion of font struct */
     font->ascent = lrint([sfont ascender]);
-    font->descent = -lrint(floor([sfont descender]));
-    font->min_width = ns_char_width(sfont, '|');
+    font->descent = -lrint(floor(adjusted_descender));
     font->space_width = lrint (ns_char_width (sfont, ' '));
-    font->average_width = lrint (font_info->width);
     font->max_width = lrint (font_info->max_bounds.width);
+    font->min_width = font->space_width;  /* Approximate.  */
+    font->average_width = ns_ascii_average_width (sfont);
+
     font->height = lrint (font_info->height);
     font->underline_position = lrint (font_info->underpos);
     font->underline_thickness = lrint (font_info->underwidth);
@@ -896,7 +916,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
     font->props[FONT_FULLNAME_INDEX] =
       make_unibyte_string (font_info->name, strlen (font_info->name));
   }
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   return font_object;
 }
@@ -972,7 +992,7 @@ nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
   int totalWidth = 0;
   int i;
 
-  bzero (metrics, sizeof (struct font_metrics));
+  memset (metrics, 0, sizeof (struct font_metrics));
 
   for (i =0; i<nglyphs; i++)
     {
@@ -1004,12 +1024,12 @@ nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
 
 
 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
-   position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
-   is nonzero, fill the background in advance.  It is assured that
-   WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
+   position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND,
+   fill the background in advance.  It is assured that WITH_BACKGROUND
+   is false when (FROM > 0 || TO < S->nchars). */
 static int
 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
-             int with_background)
+             bool with_background)
 /* NOTE: focus and clip must be set
      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
 {
@@ -1038,8 +1058,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
       face = s->face;
       break;
     case NS_DUMPGLYPH_MOUSEFACE:
-      face = FACE_FROM_ID (s->f,
-                           FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
+      face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
       if (!face)
         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
       break;
@@ -1058,7 +1077,6 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
      NS to render the string, it will come out differently from the individual
      character widths added up because of layout processing. */
   {
-    XCharStruct *cs;
     int cwidth, twidth = 0;
     int hi, lo;
     /* FIXME: composition: no vertical displacement is considered. */
@@ -1157,7 +1175,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
 
 
   /* set up for character rendering */
-  r.origin.y += font->voffset + (s->height - font->height)/2;
+  r.origin.y = s->ybase;
 
   col = (NS_FACE_FOREGROUND (face) != 0
          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
@@ -1188,20 +1206,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
       }
 
-    /* do underline */
-    if (face->underline_p)
-      {
-        if (face->underline_color != 0)
-          [ns_lookup_indexed_color (face->underline_color, s->f) set];
-        else
-          [col set];
-        DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
-        DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
-        if (face->underline_color != 0)
-          [col set];
-      }
-    else
-      [col set];
+    [col set];
 
     /* draw with DPSxshow () */
     DPSmoveto (context, r.origin.x, r.origin.y);
@@ -1209,7 +1214,6 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
     DPSstroke (context);
 
     DPSgrestore (context);
-    return to-from;
   }
 
 #else  /* NS_IMPL_COCOA */
@@ -1236,6 +1240,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
     else
       CGContextSetShouldAntialias (gcontext, 1);
 
+    CGContextSetShouldSmoothFonts (gcontext, NO);
     CGContextSetTextMatrix (gcontext, fliptf);
 
     if (bgCol != nil)
@@ -1248,23 +1253,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
       }
 
-    if (face->underline_p)
-      {
-        if (face->underline_color != 0)
-          [ns_lookup_indexed_color (face->underline_color, s->f) set];
-        else
-          [col set];
-        CGContextBeginPath (gcontext);
-        CGContextMoveToPoint (gcontext,
-                              r.origin.x, r.origin.y + font->underpos);
-        CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
-                                r.origin.y + font->underpos);
-        CGContextStrokePath (gcontext);
-        if (face->underline_color != 0)
-          [col set];
-      }
-    else
-      [col set];
+    [col set];
 
     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
@@ -1278,10 +1267,13 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
       }
 
     CGContextRestoreGState (gcontext);
-    return;
   }
 #endif  /* NS_IMPL_COCOA */
 
+  /* Draw underline, overline, strike-through. */
+  ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
+
+  return to-from;
 }
 
 
@@ -1309,7 +1301,7 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
             font_info, block);
 
BLOCK_INPUT;
 block_input ();
 
 #ifdef NS_IMPL_COCOA
   if (firstTime)
@@ -1321,10 +1313,10 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
 
   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
   if (!unichars || !(font_info->glyphs[block]))
-    abort ();
+    emacs_abort ();
 
-  /* create a string containing all unicode characters in this block */
-  for (idx = block<<8, i =0; i<0x100; idx++, i++)
+  /* create a string containing all Unicode characters in this block */
+  for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
     if (idx < 0xD800 || idx > 0xDFFF)
       unichars[i] = idx;
     else
@@ -1340,7 +1332,7 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
-    NSUInteger gInd =0, cInd =0;
+    NSUInteger gInd = 0, cInd = 0;
 
     [glyphStorage setString: allChars font: font_info->nsfont];
     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
@@ -1348,7 +1340,7 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
                                        glyphIndex: &gInd characterIndex: &cInd];
 #endif
     glyphs = font_info->glyphs[block];
-    for (i =0; i<0x100; i++, glyphs++)
+    for (i = 0; i < 0x100; i++, glyphs++)
       {
 #ifdef NS_IMPL_GNUSTEP
         g = unichars[i];
@@ -1366,7 +1358,7 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
 #endif
   }
 
-  UNBLOCK_INPUT;
+  unblock_input ();
   xfree (unichars);
 }
 
@@ -1391,13 +1383,17 @@ ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
     numGlyphs = 0x10000;
 #endif
 
- BLOCK_INPUT;
- sfont = [font_info->nsfont screenFont];
+  block_input ();
+#ifdef NS_IMPL_COCOA
+  sfont = [font_info->nsfont screenFontWithRenderingMode:
+                      NSFontAntialiasedIntegerAdvancementsRenderingMode];
+#else
+  sfont = [font_info->nsfont screenFont];
+#endif
 
-  font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
-  bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
+  font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
   if (!(font_info->metrics[block]))
-    abort ();
+    emacs_abort ();
 
   metrics = font_info->metrics[block];
   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
@@ -1421,7 +1417,7 @@ ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
       metrics->ascent = r.size.height - metrics->descent;
 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
     }
-  UNBLOCK_INPUT;
+  unblock_input ();
 }
 
 
@@ -1440,7 +1436,7 @@ ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
   maxChar = 0;
   maxGlyph = 0;
   dict = [NSMutableDictionary new];
-  cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
+  cglyphs = xmalloc (c * sizeof (CGGlyph));
   return self;
 }
 
@@ -1456,6 +1452,8 @@ ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
 - (void) setString: (NSString *)str font: (NSFont *)font
 {
   [dict setObject: font forKey: NSFontAttributeName];
+  if (attrStr != nil)
+    [attrStr release];
   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
   maxChar = [str length];
   maxGlyph = 0;
@@ -1510,15 +1508,17 @@ ns_dump_glyphstring (struct glyph_string *s)
 
 
 void
-syms_of_nsfont ()
+syms_of_nsfont (void)
 {
   nsfont_driver.type = Qns;
   register_font_driver (&nsfont_driver, NULL);
+  DEFSYM (Qcondensed, "condensed");
+  DEFSYM (Qexpanded, "expanded");
   DEFSYM (Qapple, "apple");
   DEFSYM (Qroman, "roman");
   DEFSYM (Qmedium, "medium");
-  DEFVAR_LISP ("ns-reg-to-script", &Vns_reg_to_script,
-               doc: /* Internal use: maps font registry to unicode script. */);
-}
+  DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
+               doc: /* Internal use: maps font registry to Unicode script. */);
 
-// arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae
+  ascii_printable = NULL;
+}