Commit a68fda4a authored by Adrian Robert's avatar Adrian Robert

adding forgotten file src/nsfont.m for emacs.app merge

parent edfda783
2008-07-15 Adrian Robert <Adrian.B.Robert@gmail.com>
* Makefile.in: Correct additions for nsfont.o in last commit.
* nsfont.m: New file (forgot last commit).
2008-07-15 Adrian Robert <Adrian.B.Robert@gmail.com>
Changes and additions for NeXTstep windowing system (Cocoa and
......
......@@ -535,7 +535,6 @@ emacsappsrc = ${srcdir}/../mac/Emacs.app/
NS_OBJ= nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o \
fontset.o fringe.o image.o
emacsapp = $(PWD)/../nextstep/build/Emacs.app/
FONT_DRIVERS = nsfont.o
#ifdef GNUSTEP
emacsappsrc = ${srcdir}/../nextstep/GNUstep/Emacs.base
emacsbindir = $(emacsapp)
......@@ -580,7 +579,7 @@ obj= dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
SOME_MACHINE_OBJECTS = dosfns.o msdos.o \
xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \
mac.o macterm.o macfns.o macmenu.o macselect.o fontset.o \
nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o \
nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o \
w32.o w32console.o w32fns.o w32heap.o w32inevt.o \
w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o $(FONT_DRIVERS)
......
/* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
See font.h
Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
Author: Adrian Robert (arobert@cogsci.ucsd.edu)
*/
#include "config.h"
#include "lisp.h"
#include "dispextern.h"
#include "composite.h"
#include "blockinput.h"
#include "charset.h"
#include "frame.h"
#include "window.h"
#include "fontset.h"
#include "nsterm.h"
#include "frame.h"
#include "character.h"
#include "font.h"
#define NSFONT_TRACE 0
extern Lisp_Object Qns;
extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
static Lisp_Object Qapple, Qroman, Qmedium;
extern Lisp_Object ns_expand_space;
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;
/* 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_glyph_metrics (struct nsfont_info *font_info,
unsigned char block);
/* ==========================================================================
Utilities
========================================================================== */
/* Replace spaces w/another character so emacs core font parsing routines
aren't thrown off. */
static void
nsfont_escape_name (char *name)
{
int i =0, len =strlen (name);
for ( ; i<len; i++)
if (name[i] == ' ')
name[i] = '_';
}
/* Reconstruct spaces in a font family name passed through emacs. */
static void
nsfont_unescape_name (char *name)
{
int i =0, len =strlen (name);
for ( ; i<len; i++)
if (name[i] == '_')
name[i] = ' ';
}
/* Extract family name from a font spec. */
static NSString *
nsfont_get_family (Lisp_Object font_spec)
{
Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
if (NILP (tem))
return nil;
else
{
char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
NSString *family;
nsfont_unescape_name (tmp);
/* PENDING: this seems to be needed only for font names that are
hard-coded into emacs, like 'helvetica' for splash screen */
if (tmp)
tmp[0] = toupper (tmp[0]);
family = [NSString stringWithUTF8String: tmp];
free (tmp);
return family;
}
}
/* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
/* PENDING (20080601): The font backend's strategy for handling font
styles continues to evolve. When/if this stabilizes, we
can change the code here to be more sophisticated and accurate.
For now, we rely on "normal/plain" style being numeric 100. */
#define STYLE_REF 100
static unsigned int
nsfont_spec_to_traits (Lisp_Object font_spec)
{
unsigned int traits = 0;
int n;
n = FONT_WEIGHT_NUMERIC (font_spec);
if (n != -1)
traits |= (n > STYLE_REF) ? NSBoldFontMask : NSUnboldFontMask;
n = FONT_SLANT_NUMERIC (font_spec);
if (n != -1)
traits |= (n > STYLE_REF) ? NSItalicFontMask : NSUnitalicFontMask;
n = FONT_WIDTH_NUMERIC (font_spec);
if (n > -1)
{
if (n < STYLE_REF - 10)
traits |= NSCondensedFontMask;
else if (n > STYLE_REF + 10)
traits |= NSExpandedFontMask;
}
/*fprintf (stderr, " returning traits = %u\n", traits); */
return traits;
}
/* Converts NSArray of PS name, non-family part, weight, and traits to a
font backend font-entity. */
static Lisp_Object
nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
{
Lisp_Object font_entity = font_make_entity ();
unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
/* NSString *psName = [famMember objectAtIndex: 0]; */
NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
char *escapedFamily = [family UTF8String];
nsfont_escape_name (escapedFamily);
[suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
range: NSMakeRange (0, [suffix length])];
ASET (font_entity, FONT_TYPE_INDEX, Qns);
ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
traits & NSBoldFontMask ? Qbold : Qmedium);
FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
traits & NSCondensedFontMask ? Qcondensed :
traits & NSExpandedFontMask ? Qexpanded : Qnormal);
ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
if (NSFONT_TRACE)
{
fprintf (stderr, "created font_entity:\n ");
debug_print (font_entity);
}
[suffix release];
return font_entity;
}
/* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
static int
nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
{
int i, d =0;
for (i =0; i<sizeof (unsigned int)*8; i++)
{
d += (traits1 & 0x1) ^ (traits2 & 0x1);
traits1 >> 1;
traits2 >> 1;
}
return d;
}
/* Default font entity based on Monaco. */
static Lisp_Object
nsfont_fallback_entity ()
{
NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
[NSNumber numberWithUnsignedInt: 5],
[NSNumber numberWithUnsignedInt: 0], nil];
return nsfont_fmember_to_entity (family, famMemberSpec);
}
/* ==========================================================================
Font driver implementation
========================================================================== */
static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
static Lisp_Object nsfont_list_family (Lisp_Object frame);
static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
int pixel_size);
static void nsfont_close (FRAME_PTR f, struct font *font);
static int nsfont_has_char (Lisp_Object entity, int c);
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);
struct font_driver nsfont_driver =
{
(Lisp_Object) NULL, /* Qns */
1, /* case sensitive */
nsfont_get_cache,
nsfont_list,
nsfont_match,
nsfont_list_family,
NULL, /*free_entity */
nsfont_open,
nsfont_close,
NULL, /* prepare_face */
NULL, /* done_face */
nsfont_has_char,
nsfont_encode_char,
nsfont_text_extents,
nsfont_draw,
/* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
anchor_point, otf_capability, otf_driver,
start_for_frame, end_for_frame, shape */
};
/* Return a cache of font-entities on FRAME. The cache must be a
cons whose cdr part is the actual cache area. */
static Lisp_Object
nsfont_get_cache (FRAME_PTR frame)
{
Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
return (dpyinfo->name_list_element);
}
/* List fonts exactly matching with FONT_SPEC on FRAME. The value
is a vector of font-entities. This is the sole API that
allocates font-entities. */
static Lisp_Object
nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
{
Lisp_Object list = Qnil;
Lisp_Object tem;
NSString *family;
NSArray *families;
NSEnumerator *famEnum;
NSFontManager *fontMgr;
unsigned int traits = nsfont_spec_to_traits (font_spec);
if (NSFONT_TRACE)
{
fprintf (stderr, "nsfont: list for fontspec:\n ");
debug_print (font_spec);
}
/* if has non-unicode registry, give up */
tem = AREF (font_spec, FONT_REGISTRY_INDEX);
if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
return Qnil;
fontMgr = [NSFontManager sharedFontManager];
family = nsfont_get_family (font_spec);
if (family != nil)
families = [NSArray arrayWithObject: family];
else
families = [fontMgr availableFontFamilies];
for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
{
NSEnumerator *fm;
NSArray *fmember, *firstMember = nil;
unsigned int mtraits;
BOOL foundItal = NO || (traits & NSUnitalicFontMask);
NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
#ifdef NS_IMPL_COCOA
/* LastResort is special: not a family but a font name only */
if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
{
famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
@"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
[NSNumber numberWithUnsignedInt: 0], nil]];
}
#endif
/* fmember = [postscriptName style weight traits] */
fm = [famMembers objectEnumerator];
while (fmember = [fm nextObject])
{
mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
if ((mtraits & traits) == traits)
{
list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
if (mtraits & NSItalicFontMask)
foundItal = YES;
if (firstMember == nil)
firstMember = fmember;
}
}
if (foundItal == NO && firstMember != nil)
{
/* no italic member found; add a synthesized one */
NSMutableArray *smember = [firstMember mutableCopy];
[smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
mtraits |= NSItalicFontMask;
[smember replaceObjectAtIndex: 3
withObject: [NSNumber numberWithUnsignedInt: mtraits]];
/*NSLog (@"-- adding synthItal member: %@", smember); */
list = Fcons (nsfont_fmember_to_entity (family, smember), list);
[smember release];
}
}
if (NSFONT_TRACE)
fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
return (NILP (list) ? Qnil : Fvconcat (1, &list));/* Qnil was null_vector */
}
/* Return a font entity most closely maching with FONT_SPEC on
FRAME. The closeness is determined by the font backend, thus
`face-font-selection-order' is ignored here. */
static Lisp_Object
nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
{
long traits = nsfont_spec_to_traits (font_spec);
NSFontManager *fontMgr = [NSFontManager sharedFontManager];
NSString *family;
Lisp_Object tem;
if (NSFONT_TRACE)
{
fprintf (stderr, "nsfont: match for fontspec:\n ");
debug_print (font_spec);
}
/* if has non-unicode registry, just return fallback */
#if 0
tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
if (!NILP (tem))
fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
#endif
tem = AREF (font_spec, FONT_REGISTRY_INDEX);
if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
return nsfont_fallback_entity ();
family = nsfont_get_family (font_spec);
if (family != nil)
{
/* try to find close font in family */
NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
NSEnumerator *fm = [famMembers objectEnumerator];
NSArray *fmember;
int minDist = sizeof (unsigned int) * 8 + 1;
int bestMatchIdx = -1;
int i;
for (i =0; fmember = [fm nextObject]; i++)
{
unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
int dist = nsfont_trait_distance ((mtraits & traits), traits);
if (dist < minDist)
{
bestMatchIdx = i;
minDist = dist;
}
}
if (bestMatchIdx != -1)
return nsfont_fmember_to_entity
(family, [famMembers objectAtIndex: bestMatchIdx]);
}
/* no family that had members was given; find any font matching traits */
{
NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
if (fontNames && [fontNames count] > 0)
{
NSString *fontName = [fontNames objectAtIndex: 0];
/*PENDING: is there a more efficient way to get family name? */
NSFont *font = [NSFont fontWithName: fontName size: 0];
if (font != nil)
{
/* now need to get suffix part of name.. */
NSString *family = [font familyName];
NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
objectEnumerator];
NSArray *fmember;
while (fmember = [fm nextObject])
{
unsigned int mtraits =
[[fmember objectAtIndex: 3] unsignedIntValue];
if (mtraits & traits == traits)
return nsfont_fmember_to_entity (family, fmember);
}
}
}
}
/* if we get here, return the fallback */
if (NSFONT_TRACE)
fprintf (stderr, " *** returning fallback\n");
return nsfont_fallback_entity ();
}
/* List available families. The value is a list of family names
(symbols). */
static Lisp_Object
nsfont_list_family (Lisp_Object frame)
{
Lisp_Object list = Qnil;
NSEnumerator *families =
[[[NSFontManager sharedFontManager] availableFontFamilies]
objectEnumerator];
NSString *family;
while (family = [families nextObject])
list = Fcons (intern ([family UTF8String]), list);
/*PENDING: escape the name? */
if (NSFONT_TRACE)
fprintf (stderr, "nsfont: list families returning %d entries\n",
XINT (Flength (list)));
return list;
}
/* utility: get width of a char c in screen font sfont */
static float
nsfont_char_width (NSFont *sfont, int c)
{
float w;
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;
}
#endif
w = [sfont widthOfString: cstr];
return max (w, 2.0);
}
/* Open a font specified by FONT_ENTITY on frame F. If the font is
scalable, open it with PIXEL_SIZE. */
static Lisp_Object
nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
{
BOOL synthItal;
struct nsfont_info *font_info;
struct font *font;
unsigned int traits = nsfont_spec_to_traits (font_entity);
NSFontManager *fontMgr = [NSFontManager sharedFontManager];
NSString *family;
NSFont *nsfont, *sfont;
Lisp_Object tem;
NSRect brect;
Lisp_Object font_object;
int i;
int fixLeopardBug;
#if 0
static NSMutableDictionary *fontCache = nil;
/* 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.
2008/06/01: This is still an issue, but after font backend refactoring
caching will be more difficult, needs to be reworked before enabling. */
if (fontCache == nil)
fontCache = [[NSMutableDictionary alloc] init];
#endif
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 NULL; /*PENDING: this copies w32, but causes a segfault */
if (NSFONT_TRACE)
{
fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
debug_print (font_entity);
}
if (pixel_size <= 0)
{
/* try to get it out of frame params */
Lisp_Object tem = get_frame_param (f, Qfontsize);
pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
}
tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
9);
family = nsfont_get_family (font_entity);
if (NSFONT_TRACE)
{
fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\n",
[family UTF8String], traits, traits & NSBoldFontMask);
}
/* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
nsfont = [fontMgr fontWithFamily: family
traits: traits weight: fixLeopardBug
size: pixel_size];
/* if didn't find, try synthetic italic */
if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
{
nsfont = [fontMgr fontWithFamily: family
traits: traits & ~NSItalicFontMask
weight: fixLeopardBug size: pixel_size];
}
#ifdef NS_IMPL_COCOA
/* LastResort not really a family */
if (nsfont == nil && [@"LastResort" isEqualToString: family])
{
nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
}
#endif
if (nsfont == nil)
{
message_with_string ("*** Warning: font in family '%s' not found",
build_string ([family UTF8String]), 1);
nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
if (!nsfont)
{
fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
return NULL;
}
}
#if 0
{
NSNumber *cached = [fontCache objectForKey: nsfont];
if (cached != nil && !synthItal)
{
fprintf (stderr, "*** CACHE HIT!\n");
struct font_info *existing =
(struct nsfont_info *)[cached unsignedLongValue];
/* ... */
}
else
{
if (!synthItal)
[fontCache
setObject: [NSNumber numberWithUnsignedLong:
(unsigned long)font_info]
forKey: nsfont];
}
}
#endif
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)