/* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
See font.h
- Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2006-2012 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 <config.h>
+#include <setjmp.h>
#include "lisp.h"
#include "dispextern.h"
#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
+#import <AppKit/NSFontDescriptor.h>
+#endif
#define NSFONT_TRACE 0
extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
static Lisp_Object Qapple, Qroman, Qmedium;
extern Lisp_Object Qappend;
-extern int ns_antialias_text, ns_use_qd_smoothing;
extern float ns_antialias_threshold;
extern int ns_tmp_flags;
extern struct nsfont_info *ns_tmp_font;
return nil;
else
{
- char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
+ char *tmp = xstrdup (SDATA (SYMBOL_NAME (tem)));
NSString *family;
ns_unescape_name (tmp);
- /* For names hard-coded into emacs, like 'helvetica' for splash. */
- tmp[0] = toupper (tmp[0]);
family = [NSString stringWithUTF8String: tmp];
- free (tmp);
+ xfree (tmp);
return family;
}
}
}
-/* Return whether font has attribute set to non-standard value. */
-static BOOL
-ns_has_attribute (NSFontDescriptor *fdesc, NSString *trait)
-{
- float v = ns_attribute_fvalue (fdesc, trait);
- return v < -0.05 || v > 0.05;
-}
-
-
/* 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];
[fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
- if (family != nil)
+ 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]; */
NSString *family = [desc objectForKey: NSFontFamilyAttribute];
- char *escapedFamily = strdup ([family UTF8String]);
unsigned int traits = [desc symbolicTraits];
+ char *escapedFamily;
+
+ /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
+ if (family == nil)
+ family = [desc objectForKey: NSFontNameAttribute];
+ if (family == nil)
+ family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
+ escapedFamily = xstrdup ([family UTF8String]);
ns_escape_name (escapedFamily);
ASET (font_entity, FONT_TYPE_INDEX, Qns);
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);
return w;
}
#endif
- w = [sfont widthOfString: cstr];
+ {
+ NSDictionary *attrsDictionary =
+ [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
+ w = [cstr sizeWithAttributes: attrsDictionary].width;
+ }
return max (w, 2.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
/* 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: SDATA (SYMBOL_NAME (XCDR ((script))))]
: @"";
}
-/* Searches the :script, :lang, and :otf extra-bundle properties of the spec
- for something that can be mapped to a unicode script. Empty string returned
- if no script spec found.
- TODO: Eventually registry / encoding should be checked and mapped, but for
- now the font backend will try script/lang/otf if registry fails, so it is
- not needed. */
+/* Convert a font registry, such as */
+static NSString
+*ns_registry_to_script (char *reg)
+{
+ Lisp_Object script, r, rts = Vns_reg_to_script;
+ while CONSP (rts)
+ {
+ r = XCAR (XCAR (rts));
+ if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
+ {
+ script = XCDR (XCAR (rts));
+ return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
+ }
+ rts = XCDR (rts);
+ }
+ return @"";
+}
+
+
+/* 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. */
static NSString
*ns_get_req_script (Lisp_Object font_spec)
{
+ Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
+ /* The extra-bundle properties have priority. */
for ( ; CONSP (extra); extra = XCDR (extra))
{
Lisp_Object tmp = XCAR (extra);
return ns_otf_to_script (val);
}
}
+
+ /* If we get here, check the charset portion of the registry. */
+ if (! NILP (reg))
+ {
+ /* XXX: iso10646 is passed in for non-ascii latin-1 characters
+ (which causes box rendering if we don't treat it like iso8858-1)
+ but also for ascii (which causes unnecessary font substitution). */
+#if 0
+ if (EQ (reg, Qiso10646_1))
+ reg = Qiso8859_1;
+#endif
+ return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
+ }
+
return @"";
}
}
-/* 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)
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)
{
if ([families count] > 0 || pct < 0.05)
break;
}
+ [charset release];
}
#ifdef NS_IMPL_COCOA
if ([families count] == 0)
debug_print (font_spec);
}
- /* If has non-unicode registry, give up. */
- tem = AREF (font_spec, FONT_REGISTRY_INDEX);
- if (! NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
- return isMatch ? ns_fallback_entity () : Qnil;
-
cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
fdesc = ns_spec_to_descriptor (font_spec);
if (![cFamilies containsObject:
[desc objectForKey: NSFontFamilyAttribute]])
continue;
- list = Fcons (ns_descriptor_to_entity (desc,
+ tem = ns_descriptor_to_entity (desc,
AREF (font_spec, FONT_EXTRA_INDEX),
- NULL), list);
- if (ns_has_attribute (desc, NSFontSlantTrait))
+ NULL);
+ if (isMatch)
+ return tem;
+ list = Fcons (tem, list);
+ if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
foundItal = YES;
}
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. */
+ if (isMatch)
+ return ns_fallback_entity ();
+
if (NSFONT_TRACE)
- fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
+ fprintf (stderr, " Returning %ld entities.\n",
+ (long) XINT (Flength (list)));
return list;
}
}
-/* 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(). */
/* FIXME: escape the name? */
if (NSFONT_TRACE)
- fprintf (stderr, "nsfont: list families returning %d entries\n",
- XINT (Flength (list)));
+ fprintf (stderr, "nsfont: list families returning %ld entries\n",
+ (long) XINT (Flength (list)));
return list;
}
synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
9);
family = ns_get_family (font_entity);
- if (ns_has_attribute (fontDesc, NSFontWeightTrait))
+ if (family == nil)
+ family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
+ /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
+ when setting family in ns_spec_to_descriptor(). */
+ if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
traits |= NSBoldFontMask;
- if (ns_has_attribute (fontDesc, NSFontSlantTrait))
+ if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
traits |= NSItalicFontMask;
/* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
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 *));
+ memset (font_info->glyphs, 0, 0x100 * sizeof (unsigned short *));
+ memset (font_info->metrics, 0, 0x100 * sizeof (struct font_metrics *));
BLOCK_INPUT;
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;
#else
[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 = (char *)xmalloc (strlen (fontName)+1);
+ strcpy (font_info->name, fontName);
font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
font_info->ital =
synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
[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);
- font_info->max_bounds.descent =
- -lrint (hshrink* [sfont descender] - expand*hd/2);
+ 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(adjusted_descender));
font_info->height =
font_info->max_bounds.ascent + font_info->max_bounds.descent;
font_info->max_bounds.width = lrint (font_info->width);
#endif
/* set up metrics portion of font struct */
- font->ascent = [sfont ascender];
- font->descent = -[sfont descender];
- font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
+ 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);
int totalWidth = 0;
int i;
- bzero (metrics, sizeof (struct font_metrics));
+ memset (metrics, 0, sizeof (struct font_metrics));
for (i =0; i<nglyphs; i++)
{
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;
/* 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)
/*[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);
DPSstroke (context);
DPSgrestore (context);
- return to-from;
}
#else /* NS_IMPL_COCOA */
CGContextSetFont (gcontext, font->cgfont);
CGContextSetFontSize (gcontext, font->size);
- if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
+ if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
CGContextSetShouldAntialias (gcontext, 0);
else
CGContextSetShouldAntialias (gcontext, 1);
- if (EQ (ns_use_qd_smoothing, Qt))
- CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
CGContextSetTextMatrix (gcontext, fliptf);
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,
}
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;
}
if (!unichars || !(font_info->glyphs[block]))
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
NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
/*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
- unsigned int gInd =0, cInd =0;
+ NSUInteger gInd = 0, cInd = 0;
[glyphStorage setString: allChars font: font_info->nsfont];
[glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
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];
sfont = [font_info->nsfont screenFont];
font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
- bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
+ memset (font_info->metrics[block], 0, 0x100 * sizeof (struct font_metrics));
if (!(font_info->metrics[block]))
abort ();
float w, lb, rb;
NSRect r = [sfont boundingRectForGlyph: g];
-#ifdef NS_IMPL_GNUSTEP
- {
- /* lord help us */
- NSString *s = [NSString stringWithFormat: @"%c", g];
- w = [sfont widthOfString: s];
- }
-#else
- w = [sfont advancementForGlyph: g].width;
-#endif
- w = max (w, 2.0);
+ w = max ([sfont advancementForGlyph: g].width, 2.0);
metrics->width = lrint (w);
lb = r.origin.x;
- (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;
}
/* NSGlyphStorage protocol */
-- (unsigned int)layoutOptions
+- (NSUInteger)layoutOptions
{
return 0;
}
return attrStr;
}
-- (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
- forStartingGlyphAtIndex: (unsigned int)glyphIndex
- characterIndex: (unsigned int)charIndex
+- (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
+ forStartingGlyphAtIndex: (NSUInteger)glyphIndex
+ characterIndex: (NSUInteger)charIndex
{
len = glyphIndex+length;
for (i =glyphIndex; i<len; i++)
maxGlyph = len;
}
-- (void)setIntAttribute: (int)attributeTag value: (int)val
- forGlyphAtIndex: (unsigned)glyphIndex
+- (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
+ forGlyphAtIndex: (NSUInteger)glyphIndex
{
return;
}
void
-syms_of_nsfont ()
+syms_of_nsfont (void)
{
nsfont_driver.type = Qns;
register_font_driver (&nsfont_driver, NULL);
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. */);
}
-
-// arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae