/* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
See font.h
- Copyright (C) 2006-2012 Free Software Foundation, Inc.
+ Copyright (C) 2006-2013 Free Software Foundation, Inc.
This file is part of GNU Emacs.
/* 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 "lisp.h"
#include "dispextern.h"
#endif
#define NSFONT_TRACE 0
+#define LCD_SMOOTHING_MARGIN 2
extern Lisp_Object Qns;
-extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
+extern Lisp_Object Qnormal, Qbold, Qitalic;
static Lisp_Object Qapple, Qroman, Qmedium;
+static Lisp_Object Qcondensed, Qexpanded;
extern Lisp_Object Qappend;
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);
static void
ns_escape_name (char *name)
{
- int i =0, len =strlen (name);
- for ( ; i<len; i++)
- if (name[i] == ' ')
- name[i] = '_';
+ for (; *name; name++)
+ if (*name == ' ')
+ *name = '_';
}
static void
ns_unescape_name (char *name)
{
- int i =0, len =strlen (name);
- for ( ; i<len; i++)
- if (name[i] == '_')
- name[i] = ' ';
+ for (; *name; name++)
+ if (*name == '_')
+ *name = ' ';
}
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)));*/
}
-/* 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);
}
while CONSP (rts)
{
r = XCAR (XCAR (rts));
- if (!strncmp(SSDATA(r), reg, strlen(SSDATA(r))))
+ if (!strncmp (SSDATA (r), reg, SBYTES (r)))
{
script = XCDR (XCAR (rts));
return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
NSSet *cFamilies;
BOOL foundItal = NO;
+ block_input ();
if (NSFONT_TRACE)
{
fprintf (stderr, "nsfont: %s for fontspec:\n ",
[fkeys removeObject: NSFontFamilyAttribute];
matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
+
if (NSFONT_TRACE)
NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
[matchingDescs count]);
[s1 release];
}
+ unblock_input ();
+
/* Return something if was a match and nothing found. */
if (isMatch)
return ns_fallback_entity ();
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 =
{
nsfont_list_family (Lisp_Object frame)
{
Lisp_Object list = Qnil;
- NSEnumerator *families =
- [[[NSFontManager sharedFontManager] availableFontFamilies]
- objectEnumerator];
+ NSEnumerator *families;
NSString *family;
+
+ block_input ();
+ families = [[[NSFontManager sharedFontManager] availableFontFamilies]
+ objectEnumerator];
while ((family = [families nextObject]))
list = Fcons (intern ([family UTF8String]), list);
/* FIXME: escape the name? */
fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
XINT (Flength (list)));
+ unblock_input ();
return list;
}
NSRect brect;
Lisp_Object font_object;
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];
+ block_input ();
if (NSFONT_TRACE)
{
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 */
+ {
+ unblock_input ();
+ return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
+ }
font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
- BLOCK_INPUT;
-
/* for metrics */
+#ifdef NS_IMPL_COCOA
+ sfont = [nsfont screenFontWithRenderingMode:
+ NSFontAntialiasedIntegerAdvancementsRenderingMode];
+#else
sfont = [nsfont screenFont];
+#endif
+
if (sfont == nil)
sfont = nsfont;
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;
/* set up metrics portion of font struct */
font->ascent = lrint([sfont ascender]);
font->descent = -lrint(floor(adjusted_descender));
- font->min_width = ns_char_width(sfont, '|');
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);
font->props[FONT_FULLNAME_INDEX] =
make_unibyte_string (font_info->name, strlen (font_info->name));
}
- UNBLOCK_INPUT;
+ unblock_input ();
return font_object;
}
/* 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 */
{
char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
int end = isComposite ? s->cmp_to : s->nchars;
+ block_input ();
/* Select face based on input flags */
switch (ns_tmp_flags)
{
/* Draw underline, overline, strike-through. */
ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
+ unblock_input ();
return to-from;
}
fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
font_info, block);
- BLOCK_INPUT;
+ block_input ();
#ifdef NS_IMPL_COCOA
if (firstTime)
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++)
#endif
}
- UNBLOCK_INPUT;
+ unblock_input ();
xfree (unichars);
}
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] = 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++)
lb = r.origin.x;
rb = r.size.width - w;
+ // Add to bearing for LCD smoothing. We don't know if it is there.
if (lb < 0)
- metrics->lbearing = round (lb);
+ metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
if (font_info->ital)
rb += 0.22 * font_info->height;
- metrics->rbearing = lrint (w + rb);
+ metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
/*lrint (hshrink * [sfont ascender] + expand * hd/2); */
metrics->ascent = r.size.height - metrics->descent;
/*-lrint (hshrink* [sfont descender] - expand * hd/2); */
}
- UNBLOCK_INPUT;
+ unblock_input ();
}
{
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. */);
+
+ ascii_printable = NULL;
}