-/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system.
+/* Font back-end driver for the GNUstep window system.
See font.h
Copyright (C) 2006-2021 Free Software Foundation, Inc.
#include "termchar.h"
#include "pdumper.h"
-/* TODO: Drop once we can assume gnustep-gui 0.17.1. */
+#import <Foundation/NSException.h>
#import <AppKit/NSFontDescriptor.h>
+#import <AppKit/NSLayoutManager.h>
+#import <GNUstepGUI/GSLayoutManager.h>
+#import <GNUstepGUI/GSFontInfo.h>
#define NSFONT_TRACE 0
-#define LCD_SMOOTHING_MARGIN 2
-/* 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);
+/* Structure used by GS `shape' functions for storing layout
+ information for each glyph. Borrowed from macfont.h. */
+struct ns_glyph_layout
+{
+ /* Range of indices of the characters composed into the group of
+ glyphs that share the cursor position with this glyph. The
+ members `location' and `length' are in UTF-16 indices. */
+ NSRange comp_range;
-#define INVALID_GLYPH 0xFFFF
+ /* UTF-16 index in the source string for the first character
+ associated with this glyph. */
+ NSUInteger string_index;
-/* ==========================================================================
+ /* Horizontal and vertical adjustments of glyph position. The
+ coordinate space is that of Core Text. So, the `baseline_delta'
+ value is negative if the glyph should be placed below the
+ baseline. */
+ CGFloat advance_delta, baseline_delta;
- Utilities
+ /* Typographical width of the glyph. */
+ CGFloat advance;
- ========================================================================== */
+ /* Glyph ID of the glyph. */
+ NSGlyph glyph_id;
+};
+
+
+enum lgstring_direction
+ {
+ DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1
+ };
+
+enum gs_font_slant
+ {
+ GS_FONT_SLANT_ITALIC,
+ GS_FONT_SLANT_REVERSE_ITALIC,
+ GS_FONT_SLANT_NORMAL
+ };
+
+enum gs_font_weight
+ {
+ GS_FONT_WEIGHT_LIGHT,
+ GS_FONT_WEIGHT_BOLD,
+ GS_FONT_WEIGHT_NORMAL
+ };
+
+enum gs_font_width
+ {
+ GS_FONT_WIDTH_CONDENSED,
+ GS_FONT_WIDTH_EXPANDED,
+ GS_FONT_WIDTH_NORMAL
+ };
+
+enum gs_specified
+ {
+ GS_SPECIFIED_SLANT = 1,
+ GS_SPECIFIED_WEIGHT = 1 << 1,
+ GS_SPECIFIED_WIDTH = 1 << 2,
+ GS_SPECIFIED_FAMILY = 1 << 3,
+ GS_SPECIFIED_SPACING = 1 << 4
+ };
+struct gs_font_data
+{
+ int specified;
+ enum gs_font_slant slant;
+ enum gs_font_weight weight;
+ enum gs_font_width width;
+ bool monospace_p;
+ char *family_name;
+};
-/* Replace spaces w/another character so emacs core font parsing routines
- aren't thrown off. */
static void
-ns_escape_name (char *name)
+ns_done_font_data (struct gs_font_data *data)
{
- for (; *name; name++)
- if (*name == ' ')
- *name = '_';
+ if (data->specified & GS_SPECIFIED_FAMILY)
+ xfree (data->family_name);
}
-
-/* Reconstruct spaces in a font family name passed through emacs. */
static void
-ns_unescape_name (char *name)
+ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat)
{
- for (; *name; name++)
- if (*name == '_')
- *name = ' ';
+ NSNumber *tem;
+ NSFontSymbolicTraits traits = [desc symbolicTraits];
+ NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute];
+ NSString *family = [desc objectForKey: NSFontFamilyAttribute];
+
+ dat->specified = 0;
+
+ if (family != nil)
+ {
+ dat->specified |= GS_SPECIFIED_FAMILY;
+ dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]);
+ }
+
+ tem = [desc objectForKey: NSFontFixedAdvanceAttribute];
+
+ if ((tem != nil && [tem boolValue] != NO)
+ || (traits & NSFontMonoSpaceTrait))
+ {
+ dat->specified |= GS_SPECIFIED_SPACING;
+ dat->monospace_p = true;
+ }
+ else if (tem != nil && [tem boolValue] == NO)
+ {
+ dat->specified |= GS_SPECIFIED_SPACING;
+ dat->monospace_p = false;
+ }
+
+ if (traits & NSFontBoldTrait)
+ {
+ dat->specified |= GS_SPECIFIED_WEIGHT;
+ dat->weight = GS_FONT_WEIGHT_BOLD;
+ }
+
+ if (traits & NSFontItalicTrait)
+ {
+ dat->specified |= GS_SPECIFIED_SLANT;
+ dat->slant = GS_FONT_SLANT_ITALIC;
+ }
+
+ if (traits & NSFontCondensedTrait)
+ {
+ dat->specified |= GS_SPECIFIED_WIDTH;
+ dat->width = GS_FONT_WIDTH_CONDENSED;
+ }
+ else if (traits & NSFontExpandedTrait)
+ {
+ dat->specified |= GS_SPECIFIED_WIDTH;
+ dat->width = GS_FONT_WIDTH_EXPANDED;
+ }
+
+ if (dict != nil)
+ {
+ tem = [dict objectForKey: NSFontSlantTrait];
+
+ if (tem != nil)
+ {
+ dat->specified |= GS_SPECIFIED_SLANT;
+
+ dat->slant = [tem floatValue] > 0
+ ? GS_FONT_SLANT_ITALIC
+ : ([tem floatValue] < 0
+ ? GS_FONT_SLANT_REVERSE_ITALIC
+ : GS_FONT_SLANT_NORMAL);
+ }
+
+ tem = [dict objectForKey: NSFontWeightTrait];
+
+ if (tem != nil)
+ {
+ dat->specified |= GS_SPECIFIED_WEIGHT;
+
+ dat->weight = [tem floatValue] > 0
+ ? GS_FONT_WEIGHT_BOLD
+ : ([tem floatValue] < -0.4f
+ ? GS_FONT_WEIGHT_LIGHT
+ : GS_FONT_WEIGHT_NORMAL);
+ }
+
+ tem = [dict objectForKey: NSFontWidthTrait];
+
+ if (tem != nil)
+ {
+ dat->specified |= GS_SPECIFIED_WIDTH;
+
+ dat->width = [tem floatValue] > 0
+ ? GS_FONT_WIDTH_EXPANDED
+ : ([tem floatValue] < 0
+ ? GS_FONT_WIDTH_NORMAL
+ : GS_FONT_WIDTH_CONDENSED);
+ }
+ }
+}
+
+static bool
+ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target)
+{
+ struct gs_font_data dat;
+ struct gs_font_data t;
+
+ ns_get_font_data (desc, &dat);
+ ns_get_font_data (target, &t);
+
+ if (!(t.specified & GS_SPECIFIED_WIDTH))
+ t.width = GS_FONT_WIDTH_NORMAL;
+ if (!(t.specified & GS_SPECIFIED_WEIGHT))
+ t.weight = GS_FONT_WEIGHT_NORMAL;
+ if (!(t.specified & GS_SPECIFIED_SPACING))
+ t.monospace_p = false;
+ if (!(t.specified & GS_SPECIFIED_SLANT))
+ t.slant = GS_FONT_SLANT_NORMAL;
+
+ if (!(t.specified & GS_SPECIFIED_FAMILY))
+ emacs_abort ();
+
+ bool match_p = true;
+
+ if (dat.specified & GS_SPECIFIED_WIDTH
+ && dat.width != t.width)
+ {
+ match_p = false;
+ goto gout;
+ }
+
+ if (dat.specified & GS_SPECIFIED_WEIGHT
+ && dat.weight != t.weight)
+ {
+ match_p = false;
+ goto gout;
+ }
+
+ if (dat.specified & GS_SPECIFIED_SPACING
+ && dat.monospace_p != t.monospace_p)
+ {
+ match_p = false;
+ goto gout;
+ }
+
+ if (dat.specified & GS_SPECIFIED_SLANT
+ && dat.monospace_p != t.monospace_p)
+ {
+ if (NSFONT_TRACE)
+ printf ("Matching monospace for %s: %d %d\n",
+ t.family_name, dat.monospace_p,
+ t.monospace_p);
+ match_p = false;
+ goto gout;
+ }
+
+ if (dat.specified & GS_SPECIFIED_FAMILY
+ && strcmp (dat.family_name, t.family_name))
+ match_p = false;
+
+ gout:
+ ns_done_font_data (&dat);
+ ns_done_font_data (&t);
+
+ return match_p;
}
+/* 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 int block);
+
+#define INVALID_GLYPH 0xFFFF
+
+/* ==========================================================================
+
+ Utilities
+
+ ========================================================================== */
+
/* Extract family name from a font spec. */
static NSString *
{
char *tmp = xlispstrdup (SYMBOL_NAME (tem));
NSString *family;
- ns_unescape_name (tmp);
family = [NSString stringWithUTF8String: tmp];
xfree (tmp);
return family;
}
}
-
-/* Return 0 if attr not set, else value (which might also be 0).
- On Leopard 0 gets returned even on descriptors where the attribute
- was never set, so there's no way to distinguish between unspecified
- and set to not have. Callers should assume 0 means unspecified. */
-static float
-ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
-{
- NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
- NSNumber *val = [tdict objectForKey: trait];
- return val == nil ? 0.0F : [val floatValue];
-}
-
-
/* 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)
{
NSFontDescriptor *fdesc;
NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
- NSMutableDictionary *tdict = [NSMutableDictionary new];
NSString *family = ns_get_family (font_spec);
- float n;
-
- /* Add each attr in font_spec to fdAttrs. */
- n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
- if (n != -1 && n != STYLE_REF)
- [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
- forKey: NSFontWeightTrait];
- n = min (FONT_SLANT_NUMERIC (font_spec), 200);
- if (n != -1 && n != STYLE_REF)
- [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
- forKey: NSFontSlantTrait];
- n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
- if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
- [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
- forKey: NSFontWidthTrait];
- if ([tdict count] > 0)
- [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
+ NSMutableDictionary *tdict = [NSMutableDictionary new];
- fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
- retain] autorelease];
+ Lisp_Object tem;
+
+ tem = FONT_SLANT_SYMBOLIC (font_spec);
+ if (!NILP (tem))
+ {
+ if (EQ (tem, Qitalic) || EQ (tem, Qoblique))
+ [tdict setObject: [NSNumber numberWithFloat: 1.0]
+ forKey: NSFontSlantTrait];
+ else if (EQ (tem, intern ("reverse-italic")) ||
+ EQ (tem, intern ("reverse-oblique")))
+ [tdict setObject: [NSNumber numberWithFloat: -1.0]
+ forKey: NSFontSlantTrait];
+ else
+ [tdict setObject: [NSNumber numberWithFloat: 0.0]
+ forKey: NSFontSlantTrait];
+ }
+
+ tem = FONT_WIDTH_SYMBOLIC (font_spec);
+ if (!NILP (tem))
+ {
+ if (EQ (tem, Qcondensed))
+ [tdict setObject: [NSNumber numberWithFloat: -1.0]
+ forKey: NSFontWidthTrait];
+ else if (EQ (tem, Qexpanded))
+ [tdict setObject: [NSNumber numberWithFloat: 1.0]
+ forKey: NSFontWidthTrait];
+ else
+ [tdict setObject: [NSNumber numberWithFloat: 0.0]
+ forKey: NSFontWidthTrait];
+ }
+
+ tem = FONT_WEIGHT_SYMBOLIC (font_spec);
+
+ if (!NILP (tem))
+ {
+ if (EQ (tem, Qbold))
+ {
+ [tdict setObject: [NSNumber numberWithFloat: 1.0]
+ forKey: NSFontWeightTrait];
+ }
+ else if (EQ (tem, Qlight))
+ {
+ [tdict setObject: [NSNumber numberWithFloat: -1.0]
+ forKey: NSFontWeightTrait];
+ }
+ else
+ {
+ [tdict setObject: [NSNumber numberWithFloat: 0.0]
+ forKey: NSFontWeightTrait];
+ }
+ }
+
+ tem = AREF (font_spec, FONT_SPACING_INDEX);
if (family != nil)
{
- NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
- fdesc = [[fdesc2 retain] autorelease];
+ [fdAttrs setObject: family
+ forKey: NSFontFamilyAttribute];
}
- [fdAttrs release];
+ if (FIXNUMP (tem))
+ {
+ if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL)
+ {
+ [fdAttrs setObject: [NSNumber numberWithBool:YES]
+ forKey: NSFontFixedAdvanceAttribute];
+ }
+ else
+ {
+ [fdAttrs setObject: [NSNumber numberWithBool:NO]
+ forKey: NSFontFixedAdvanceAttribute];
+ }
+ }
+
+ /* Handle special families such as ``fixed'' or ``Sans Serif''. */
+
+ if ([family isEqualToString: @"fixed"])
+ {
+ [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName]
+ forKey: NSFontFamilyAttribute];
+ }
+ else if ([family isEqualToString: @"Sans Serif"])
+ {
+ [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName]
+ forKey: NSFontFamilyAttribute];
+ }
+
+ [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
+
+ fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
+ retain] autorelease];
+
[tdict release];
+ [fdAttrs release];
return fdesc;
}
Lisp_Object extra,
const char *style)
{
- Lisp_Object font_entity = font_make_entity ();
- /* NSString *psName = [desc postscriptName]; */
- NSString *family = [desc objectForKey: NSFontFamilyAttribute];
- 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);
- ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
- ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
- ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
- ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
-
- FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
- traits & NSFontBoldTrait ? Qbold : Qmedium);
-/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
- make_fixnum (100 + 100
- * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
- FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
- traits & NSFontItalicTrait ? Qitalic : Qnormal);
-/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
- make_fixnum (100 + 100
- * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
- FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
- traits & NSFontCondensedTrait ? Qcondensed :
- traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
-/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
- make_fixnum (100 + 100
- * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
-
- ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0));
- ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
- ASET (font_entity, FONT_SPACING_INDEX,
- make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait
- ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
-
- ASET (font_entity, FONT_EXTRA_INDEX, extra);
- ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
+ Lisp_Object font_entity = font_make_entity ();
+ struct gs_font_data data;
+ ns_get_font_data (desc, &data);
+
+ ASET (font_entity, FONT_TYPE_INDEX, Qns);
+ ASET (font_entity, FONT_FOUNDRY_INDEX, Qns);
+ if (data.specified & GS_SPECIFIED_FAMILY)
+ ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name));
+ ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
+ ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
+
+ if (data.specified & GS_SPECIFIED_WEIGHT)
+ {
+ FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
+ data.weight == GS_FONT_WEIGHT_BOLD
+ ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT
+ ? Qlight : Qnormal));
+ }
+ else
+ FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal);
- if (NSFONT_TRACE)
- {
- fputs ("created font_entity:\n ", stderr);
- debug_print (font_entity);
- }
+ if (data.specified & GS_SPECIFIED_SLANT)
+ {
+ FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
+ data.slant == GS_FONT_SLANT_ITALIC
+ ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC
+ ? intern ("reverse-italic") : Qnormal));
+ }
+ else
+ FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal);
+
+ if (data.specified & GS_SPECIFIED_WIDTH)
+ {
+ FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
+ data.width == GS_FONT_WIDTH_CONDENSED
+ ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED
+ ? intern ("expanded") : Qnormal));
+ }
+ else
+ FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal);
- xfree (escapedFamily);
- return font_entity;
+ ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0));
+ ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+ ASET (font_entity, FONT_SPACING_INDEX,
+ make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p)
+ ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
+
+ ASET (font_entity, FONT_EXTRA_INDEX, extra);
+ ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
+
+ if (NSFONT_TRACE)
+ {
+ fputs ("created font_entity:\n ", stderr);
+ debug_print (font_entity);
+ }
+
+ ns_done_font_data (&data);
+ return font_entity;
}
static Lisp_Object
ns_fallback_entity (void)
{
- return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
- fontDescriptor], Qnil, NULL);
+ return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL);
}
return families;
}
+/* GNUstep font matching is very mediocre (it can't even compare
+ symbolic styles correctly), which is why our own font matching
+ mechanism must be implemented. */
-/* Implementation for list() and match(). List() can return nil, match()
-must return something. Strategy is to drop family name from attribute
-matching set for match. */
+/* Implementation for list and match. */
static Lisp_Object
ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
{
Lisp_Object tem, list = Qnil;
- NSFontDescriptor *fdesc, *desc;
- NSMutableSet *fkeys;
- NSArray *matchingDescs;
- NSEnumerator *dEnum;
- NSString *family;
+ NSFontDescriptor *fdesc;
+ NSArray *all_descs;
+ GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator];
+
NSSet *cFamilies;
- BOOL foundItal = NO;
block_input ();
if (NSFONT_TRACE)
cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
fdesc = ns_spec_to_descriptor (font_spec);
- fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
- if (isMatch)
- [fkeys removeObject: NSFontFamilyAttribute];
-
- matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
+ all_descs = [enumerator availableFontDescriptors];
- if (NSFONT_TRACE)
- NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
- (unsigned long)[matchingDescs count]);
-
- for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
+ for (NSFontDescriptor *desc in all_descs)
{
if (![cFamilies containsObject:
[desc objectForKey: NSFontFamilyAttribute]])
continue;
+ if (!ns_font_descs_match_p (fdesc, desc))
+ continue;
+
tem = ns_descriptor_to_entity (desc,
- AREF (font_spec, FONT_EXTRA_INDEX),
+ AREF (font_spec, FONT_EXTRA_INDEX),
NULL);
if (isMatch)
return tem;
list = Fcons (tem, list);
- if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
- foundItal = YES;
- }
-
- /* Add synthItal member if needed. */
- family = [fdesc objectForKey: NSFontFamilyAttribute];
- if (family != nil && !foundItal && !NILP (list))
- {
- 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];
}
unblock_input ();
objectEnumerator];
while ((family = [families nextObject]))
list = Fcons (intern ([family UTF8String]), list);
- /* FIXME: escape the name? */
if (NSFONT_TRACE)
fprintf (stderr, "nsfont: list families returning %"pD"d entries\n",
static Lisp_Object
nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
{
- BOOL synthItal;
- unsigned int traits = 0;
struct nsfont_info *font_info;
struct font *font;
NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
NSFontManager *fontMgr = [NSFontManager sharedFontManager];
NSString *family;
NSFont *nsfont, *sfont;
- Lisp_Object tem;
NSRect brect;
Lisp_Object font_object;
- int fixLeopardBug;
+ Lisp_Object tem;
block_input ();
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 : XFIXNAT (tem);
+ tem = get_frame_param (f, Qfontsize);
+ pixel_size = NILP (tem) ? 0 : XFIXNAT (tem);
}
tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
- synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
- 9);
family = ns_get_family (font_entity);
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.50F)
- traits |= NSBoldFontMask;
- if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F)
- traits |= NSItalicFontMask;
-
- /* see https://web.archive.org/web/20100201175731/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)
- {
- nsfont = [fontMgr fontWithFamily: family
- traits: traits & ~NSItalicFontMask
- weight: fixLeopardBug size: pixel_size];
- }
+
+ nsfont = [NSFont fontWithDescriptor: fontDesc
+ size: pixel_size];
if (nsfont == nil)
- {
- message_with_string ("*** Warning: font in family `%s' not found",
- build_string ([family UTF8String]), 1);
- nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
- }
+ nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
if (NSFONT_TRACE)
NSLog (@"%@\n", nsfont);
if (!font)
{
unblock_input ();
- return Qnil; /* FIXME: other terms do, but returning Qnil causes segfault. */
+ return Qnil;
}
font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
font_info->name = xstrdup (fontName);
font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
font_info->ital =
- synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
+ ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
/* Metrics etc.; some fonts return an unusually large max advance, so we
only use it for fonts that have wide characters. */
lrint (brect.size.width - (CGFloat) font_info->width);
/* set up metrics portion of font struct */
- font->ascent = lrint([sfont ascender]);
- font->descent = -lrint(floor(adjusted_descender));
font->space_width = lrint (ns_char_width (sfont, ' '));
font->max_width = lrint (font_info->max_bounds.width);
font->min_width = font->space_width; /* Approximate. */
{
struct nsfont_info *font_info = (struct nsfont_info *)font;
unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
- unsigned short g;
+ unsigned int g;
if (c > 0xFFFF)
return FONT_INVALID_CODE;
static int
nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
bool with_background)
-/* NOTE: focus and clip must be set. */
{
- static unsigned char cbuf[1024];
- unsigned char *c = cbuf;
-#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22
- static CGFloat advances[1024];
- CGFloat *adv = advances;
-#else
- static float advances[1024];
- float *adv = advances;
-#endif
+ NSGlyph *c = alloca ((to - from) * sizeof *c);
+
struct face *face;
NSRect r;
struct nsfont_info *font;
- NSColor *col, *bgCol;
- unsigned *t = s->char2b;
- int i, len, flags;
+ NSColor *col;
+ int len = to - from;
char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
block_input ();
- font = (struct nsfont_info *)s->face->font;
+ font = (struct nsfont_info *) s->font;
if (font == NULL)
font = (struct nsfont_info *)FRAME_FONT (s->f);
- /* Select face based on input flags. */
- flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
- (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
- (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
- NS_DUMPGLYPH_NORMAL));
-
- switch (flags)
- {
- case NS_DUMPGLYPH_CURSOR:
- face = s->face;
- break;
- case NS_DUMPGLYPH_MOUSEFACE:
- face = FACE_FROM_ID_OR_NULL (s->f,
- MOUSE_HL_INFO (s->f)->mouse_face_face_id);
- if (!face)
- face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
- break;
- default:
- face = s->face;
- }
+ face = s->face;
r.origin.x = s->x;
if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
r.origin.y = s->y;
r.size.height = FONT_HEIGHT (font);
- /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
- NS to render the string, it will come out differently from the individual
- character widths added up because of layout processing. */
- {
- int cwidth, twidth = 0;
- int hi, lo;
- /* FIXME: composition: no vertical displacement is considered. */
- t += from; /* advance into composition */
- for (i = from; i < to; i++, t++)
- {
- hi = (*t & 0xFF00) >> 8;
- lo = *t & 0x00FF;
- if (isComposite)
- {
- if (!s->first_glyph->u.cmp.automatic)
- cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
- else
- {
- Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
- Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
- if (NILP (LGLYPH_ADJUSTMENT (glyph)))
- cwidth = LGLYPH_WIDTH (glyph);
- else
- {
- cwidth = LGLYPH_WADJUST (glyph);
- *(adv-1) += LGLYPH_XOFF (glyph);
- }
- }
- }
- else
- {
- if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
- ns_glyph_metrics (font, hi);
- cwidth = font->metrics[hi][lo].width;
- }
- twidth += cwidth;
- *adv++ = cwidth;
- c += CHAR_STRING (*t, c); /* This converts the char to UTF-8. */
- }
- len = adv - advances;
- r.size.width = twidth;
- *c = 0;
- }
+ for (int i = from; i < to; ++i)
+ c[i] = s->char2b[i];
/* Fill background if requested. */
if (with_background && !isComposite)
{
- NSRect br = r;
- int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
- int mbox_line_width = max (s->face->box_vertical_line_width, 0);
-
- if (s->row->full_width_p)
- {
- if (br.origin.x <= fibw + 1 + mbox_line_width)
- {
- br.size.width += br.origin.x - mbox_line_width;
- br.origin.x = mbox_line_width;
- }
- if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
- <= fibw+1)
- br.size.width += fibw;
- }
- if (s->face->box == FACE_NO_BOX)
- {
- /* Expand unboxed top row over internal border. */
- if (br.origin.y <= fibw + 1 + mbox_line_width)
- {
- br.size.height += br.origin.y;
- br.origin.y = 0;
- }
- }
- else
- {
- int correction = abs (s->face->box_horizontal_line_width)+1;
- br.origin.y += correction;
- br.size.height -= 2*correction;
- correction = abs (s->face->box_vertical_line_width)+1;
- br.origin.x += correction;
- br.size.width -= 2*correction;
- }
+ NSRect br = NSMakeRect (x, y - FONT_BASE (s->font),
+ s->width, FONT_HEIGHT (s->font));
if (!s->face->stipple)
- [(NS_FACE_BACKGROUND (face) != 0
- ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
- : FRAME_BACKGROUND_COLOR (s->f)) set];
+ {
+ if (s->hl != DRAW_CURSOR)
+ [(NS_FACE_BACKGROUND (face) != 0
+ ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
+ : FRAME_BACKGROUND_COLOR (s->f)) set];
+ else
+ [FRAME_CURSOR_COLOR (s->f) set];
+ }
else
{
struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
NSRectFill (br);
}
-
/* set up for character rendering */
r.origin.y = y;
- col = (NS_FACE_FOREGROUND (face) != 0
- ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
- : FRAME_FOREGROUND_COLOR (s->f));
-
- bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
- : (NS_FACE_BACKGROUND (face) != 0
- ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
- : FRAME_BACKGROUND_COLOR (s->f)));
+ if (s->hl == DRAW_CURSOR)
+ col = FRAME_BACKGROUND_COLOR (s->f);
+ else
+ col = (NS_FACE_FOREGROUND (face) != 0
+ ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
+ : FRAME_FOREGROUND_COLOR (s->f));
/* render under GNUstep using DPS */
{
- NSGraphicsContext *context = GSCurrentContext ();
-
+ NSGraphicsContext *context = [NSGraphicsContext currentContext];
DPSgsave (context);
- [font->nsfont set];
-
- /* do erase if "foreground" mode */
- if (bgCol != nil)
+ if (s->clip_head)
{
- [bgCol set];
- DPSmoveto (context, r.origin.x, r.origin.y);
-/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
- DPSxshow (context, (const char *) cbuf, advances, len);
- DPSstroke (context);
- [col set];
-/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
+ DPSrectclip (context, s->clip_head->x, 0,
+ FRAME_PIXEL_WIDTH (s->f),
+ FRAME_PIXEL_HEIGHT (s->f));
}
+ [font->nsfont set];
[col set];
- /* draw with DPSxshow () */
DPSmoveto (context, r.origin.x, r.origin.y);
- DPSxshow (context, (const char *) cbuf, advances, len);
+ GSShowGlyphs (context, c, len);
DPSstroke (context);
DPSgrestore (context);
return to-from;
}
+static NSUInteger
+ns_font_shape (NSFont *font, NSString *string,
+ struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len,
+ enum lgstring_direction dir)
+{
+ NSUInteger i;
+ NSUInteger result = 0;
+ NSTextStorage *textStorage;
+ NSLayoutManager *layoutManager;
+ NSTextContainer *textContainer;
+ NSUInteger stringLength;
+ NSPoint spaceLocation;
+ /* numberOfGlyphs can't actually be 0, but this pacifies GCC */
+ NSUInteger used, numberOfGlyphs = 0;
+
+ textStorage = [[NSTextStorage alloc] initWithString:string];
+ layoutManager = [[NSLayoutManager alloc] init];
+ textContainer = [[NSTextContainer alloc] init];
+
+ /* Append a trailing space to measure baseline position. */
+ [textStorage appendAttributedString:([[[NSAttributedString alloc]
+ initWithString:@" "] autorelease])];
+ [textStorage setFont:font];
+ [textContainer setLineFragmentPadding:0];
+
+ [layoutManager addTextContainer:textContainer];
+ [textContainer release];
+ [textStorage addLayoutManager:layoutManager];
+ [layoutManager release];
+
+ if (!(textStorage && layoutManager && textContainer))
+ emacs_abort ();
+
+ stringLength = [string length];
+
+ /* Force layout. */
+ (void) [layoutManager glyphRangeForTextContainer:textContainer];
+
+ spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
+
+ /* Remove the appended trailing space because otherwise it may
+ generate a wrong result for a right-to-left text. */
+ [textStorage beginEditing];
+ [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
+ [textStorage endEditing];
+ (void) [layoutManager glyphRangeForTextContainer:textContainer];
+
+ i = 0;
+ while (i < stringLength)
+ {
+ NSRange range;
+ NSFont *fontInTextStorage =
+ [textStorage attribute: NSFontAttributeName
+ atIndex:i
+ longestEffectiveRange: &range
+ inRange: NSMakeRange (0, stringLength)];
+
+ if (!(fontInTextStorage == font
+ || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
+ break;
+ i = NSMaxRange (range);
+ }
+ if (i < stringLength)
+ /* Make the test `used <= glyph_len' below fail if textStorage
+ contained some fonts other than the specified one. */
+ used = glyph_len + 1;
+ else
+ {
+ NSRange range = NSMakeRange (0, stringLength);
+
+ range = [layoutManager glyphRangeForCharacterRange:range
+ actualCharacterRange:NULL];
+ numberOfGlyphs = NSMaxRange (range);
+ used = numberOfGlyphs;
+ for (i = 0; i < numberOfGlyphs; i++)
+ if ([layoutManager notShownAttributeForGlyphAtIndex:i])
+ used--;
+ }
+
+ if (0 < used && used <= glyph_len)
+ {
+ NSUInteger glyphIndex, prevGlyphIndex;
+ NSUInteger *permutation;
+ NSRange compRange, range;
+ CGFloat totalAdvance;
+
+ glyphIndex = 0;
+ while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
+ glyphIndex++;
+
+ permutation = NULL;
+#define RIGHT_TO_LEFT_P permutation
+
+ /* Fill the `comp_range' member of struct mac_glyph_layout, and
+ setup a permutation for right-to-left text. */
+ compRange = NSMakeRange (0, 0);
+ for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
+ range.length++)
+ {
+ struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
+ NSUInteger characterIndex =
+ [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
+
+ gl->string_index = characterIndex;
+
+ if (characterIndex >= NSMaxRange (compRange))
+ {
+ compRange.location = NSMaxRange (compRange);
+ do
+ {
+ NSRange characterRange =
+ [string
+ rangeOfComposedCharacterSequenceAtIndex:characterIndex];
+
+ compRange.length =
+ NSMaxRange (characterRange) - compRange.location;
+ [layoutManager glyphRangeForCharacterRange:compRange
+ actualCharacterRange:&characterRange];
+ characterIndex = NSMaxRange (characterRange) - 1;
+ }
+ while (characterIndex >= NSMaxRange (compRange));
+
+ if (RIGHT_TO_LEFT_P)
+ for (i = 0; i < range.length; i++)
+ permutation[range.location + i] = NSMaxRange (range) - i - 1;
+
+ range = NSMakeRange (NSMaxRange (range), 0);
+ }
+
+ gl->comp_range.location = compRange.location;
+ gl->comp_range.length = compRange.length;
+
+ while (++glyphIndex < numberOfGlyphs)
+ if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
+ break;
+ }
+ if (RIGHT_TO_LEFT_P)
+ for (i = 0; i < range.length; i++)
+ permutation[range.location + i] = NSMaxRange (range) - i - 1;
+
+ /* Then fill the remaining members. */
+ glyphIndex = prevGlyphIndex = 0;
+ while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
+ glyphIndex++;
+
+ if (!RIGHT_TO_LEFT_P)
+ totalAdvance = 0;
+ else
+ {
+ NSUInteger nrects;
+ NSRect *glyphRects =
+ [layoutManager
+ rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
+ withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
+ inTextContainer:textContainer rectCount:&nrects];
+
+ totalAdvance = NSMaxX (glyphRects[0]);
+ }
+
+ for (i = 0; i < used; i++)
+ {
+ struct ns_glyph_layout *gl;
+ NSPoint location;
+ NSUInteger nextGlyphIndex;
+ NSRange glyphRange;
+ NSRect *glyphRects;
+ NSUInteger nrects;
+
+ if (!RIGHT_TO_LEFT_P)
+ gl = glyph_layouts + i;
+ else
+ {
+ NSUInteger dest = permutation[i];
+
+ gl = glyph_layouts + dest;
+ if (i < dest)
+ {
+ NSUInteger tmp = gl->string_index;
+
+ gl->string_index = glyph_layouts[i].string_index;
+ glyph_layouts[i].string_index = tmp;
+ }
+ }
+ gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex];
+
+ location = [layoutManager locationForGlyphAtIndex:glyphIndex];
+ gl->baseline_delta = spaceLocation.y - location.y;
+
+ for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
+ nextGlyphIndex++)
+ if (![layoutManager
+ notShownAttributeForGlyphAtIndex:nextGlyphIndex])
+ break;
+
+ if (!RIGHT_TO_LEFT_P)
+ {
+ CGFloat maxX;
+
+ if (prevGlyphIndex == 0)
+ glyphRange = NSMakeRange (0, nextGlyphIndex);
+ else
+ glyphRange = NSMakeRange (glyphIndex,
+ nextGlyphIndex - glyphIndex);
+ glyphRects =
+ [layoutManager
+ rectArrayForGlyphRange:glyphRange
+ withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
+ inTextContainer:textContainer rectCount:&nrects];
+ maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
+ gl->advance_delta = location.x - totalAdvance;
+ gl->advance = maxX - totalAdvance;
+ totalAdvance = maxX;
+ }
+ else
+ {
+ CGFloat minX;
+
+ if (nextGlyphIndex == numberOfGlyphs)
+ glyphRange = NSMakeRange (prevGlyphIndex,
+ numberOfGlyphs - prevGlyphIndex);
+ else
+ glyphRange = NSMakeRange (prevGlyphIndex,
+ glyphIndex + 1 - prevGlyphIndex);
+ glyphRects =
+ [layoutManager
+ rectArrayForGlyphRange:glyphRange
+ withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
+ inTextContainer:textContainer rectCount:&nrects];
+ minX = min (NSMinX (glyphRects[0]), totalAdvance);
+ gl->advance = totalAdvance - minX;
+ totalAdvance = minX;
+ gl->advance_delta = location.x - totalAdvance;
+ }
+
+ prevGlyphIndex = glyphIndex + 1;
+ glyphIndex = nextGlyphIndex;
+ }
+
+ if (RIGHT_TO_LEFT_P)
+ xfree (permutation);
+
+#undef RIGHT_TO_LEFT_P
+
+ result = used;
+ }
+ [textStorage release];
+
+ return result;
+}
+
+static Lisp_Object
+nsfont_shape (Lisp_Object lgstring, Lisp_Object direction)
+{
+ struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
+ struct nsfont_info *font_info = (struct nsfont_info *) font;
+ struct ns_glyph_layout *glyph_layouts;
+ NSFont *nsfont = font_info->nsfont;
+ ptrdiff_t glyph_len, len, i;
+ Lisp_Object tem;
+ unichar *mb_buf;
+ NSUInteger used;
+
+ glyph_len = LGSTRING_GLYPH_LEN (lgstring);
+ for (i = 0; i < glyph_len; ++i)
+ {
+ tem = LGSTRING_GLYPH (lgstring, i);
+
+ if (NILP (tem))
+ break;
+ }
+
+ len = i;
+
+ if (INT_MAX / 2 < len)
+ memory_full (SIZE_MAX);
+
+ block_input ();
+
+ mb_buf = alloca (len * sizeof *mb_buf);
+
+ for (i = 0; i < len; ++i)
+ {
+ uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
+ mb_buf[i] = (unichar) c;
+ }
+
+ NSString *string = [NSString stringWithCharacters: mb_buf
+ length: len];
+ unblock_input ();
+
+ if (!string)
+ return Qnil;
+
+ block_input ();
+
+ enum lgstring_direction dir = DIR_UNKNOWN;
+
+ if (EQ (direction, QL2R))
+ dir = DIR_L2R;
+ else if (EQ (direction, QR2L))
+ dir = DIR_R2L;
+ glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len);
+ used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir);
+
+ for (i = 0; i < used; i++)
+ {
+ Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
+ struct ns_glyph_layout *gl = glyph_layouts + i;
+ EMACS_INT from, to;
+ struct font_metrics metrics;
+
+ if (NILP (lglyph))
+ {
+ lglyph = LGLYPH_NEW ();
+ LGSTRING_SET_GLYPH (lgstring, i, lglyph);
+ }
+
+ from = gl->comp_range.location;
+ LGLYPH_SET_FROM (lglyph, from);
+
+ to = gl->comp_range.location + gl->comp_range.length;
+ LGLYPH_SET_TO (lglyph, to - 1);
+
+ /* LGLYPH_CHAR is used in `describe-char' for checking whether
+ the composition is trivial. */
+ {
+ UTF32Char c;
+
+ if (mb_buf[gl->string_index] >= 0xD800
+ && mb_buf[gl->string_index] < 0xDC00)
+ c = (((mb_buf[gl->string_index] - 0xD800) << 10)
+ + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000);
+ else
+ c = mb_buf[gl->string_index];
+
+ LGLYPH_SET_CHAR (lglyph, c);
+ }
+
+ {
+ unsigned long cc = gl->glyph_id;
+ LGLYPH_SET_CODE (lglyph, cc);
+ }
+
+ nsfont_text_extents (font, &gl->glyph_id, 1, &metrics);
+ LGLYPH_SET_WIDTH (lglyph, metrics.width);
+ LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
+ LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
+ LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
+ LGLYPH_SET_DESCENT (lglyph, metrics.descent);
+ }
+ unblock_input ();
+
+ return make_fixnum (used);
+}
/* ==========================================================================
========================================================================== */
+static NSGlyph
+ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c)
+{
+ unichar characters[] = { c };
+ NSString *string =
+ [NSString stringWithCharacters: characters
+ length: 1];
+ NSDictionary *attributes =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ info->nsfont, NSFontAttributeName, nil];
+ NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string
+ attributes: attributes];
+ NSTextContainer *text_container = [[NSTextContainer alloc] init];
+ NSLayoutManager *manager = [[NSLayoutManager alloc] init];
+
+ [manager addTextContainer: text_container];
+ [text_container release]; /* Retained by manager */
+ [storage addLayoutManager: manager];
+ [manager release]; /* Retained by storage */
+
+ NSFont *font_in_storage = [storage attribute: NSFontAttributeName
+ atIndex:0
+ effectiveRange: NULL];
+ NSGlyph glyph = FONT_INVALID_CODE;
+
+ if ((font_in_storage == info->nsfont
+ || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]]))
+ {
+ @try
+ {
+ glyph = [manager glyphAtIndex: 0];
+ }
+ @catch (NSException *e)
+ {
+ /* GNUstep bug? */
+ glyph = 'X';
+ }
+ }
+
+ [storage release];
+
+ return glyph;
+}
+
/* Find and cache corresponding glyph codes for unicode values in given
hi-byte block of 256. */
static void
{
unichar *unichars = xmalloc (0x101 * sizeof (unichar));
unsigned int i, g, idx;
- unsigned short *glyphs;
+ unsigned int *glyphs;
if (NSFONT_TRACE)
fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
block_input ();
- font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
+ font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int));
if (!unichars || !(font_info->glyphs[block]))
emacs_abort ();
for (i = 0; i < 0x100; i++, glyphs++)
{
g = unichars[i];
- *glyphs = g;
+ NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g);
+ *glyphs = glyph;
}
}
}
-/* Determine and cache metrics for corresponding glyph codes in given
- hi-byte block of 256. */
+/* Determine and cache metrics for glyphs in given hi-byte block of
+ 256. */
static void
-ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
+ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block)
{
- unsigned int i, g;
+ unsigned int i;
+ NSGlyph g;
unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
NSFont *sfont;
struct font_metrics *metrics;
if (NSFONT_TRACE)
- fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
+ fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n",
font_info, block);
/* not implemented yet (as of startup 0.18), so punt */
w = max ([sfont advancementForGlyph: g].width, 2.0);
metrics->width = lrint (w);
- 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 - LCD_SMOOTHING_MARGIN);
- if (font_info->ital)
- rb += (CGFloat) (0.22F * font_info->height);
- 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); */
+ lb = NSMinX (r);
+ rb = NSMaxX (r);
+
+ metrics->rbearing = lrint (rb);
+ metrics->lbearing = lrint (lb);
+
+ metrics->descent = NSMinY (r);
+ metrics->ascent = NSMaxY (r);
}
unblock_input ();
}
.has_char = nsfont_has_char,
.encode_char = nsfont_encode_char,
.text_extents = nsfont_text_extents,
+ .shape = nsfont_shape,
.draw = nsfont_draw,
};
{
DEFSYM (Qcondensed, "condensed");
DEFSYM (Qexpanded, "expanded");
- DEFSYM (Qapple, "apple");
DEFSYM (Qmedium, "medium");
DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
doc: /* Internal use: maps font registry to Unicode script. */);
/* clipping */
if (r)
{
- [[NSGraphicsContext currentContext] saveGraphicsState];
+ NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
+ [ctx saveGraphicsState];
+#ifdef NS_IMPL_COCOA
if (n == 2)
NSRectClipList (r, 2);
else
NSRectClip (*r);
+#else
+ GSRectClipList (ctx, r, n);
+#endif
gsaved = YES;
}
}
EmacsView *view = FRAME_NS_VIEW (f);
FRAME_POINTER_TYPE (f) = cursor;
[[view window] invalidateCursorRectsForView: view];
- /* Redisplay assumes this function also draws the changed frame
- cursor, but this function doesn't, so do it explicitly. */
- gui_update_cursor (f, 1);
}
}
External (RIF); compute left/right overhang of whole string and set in s
-------------------------------------------------------------------------- */
{
- struct font *font = s->font;
-
- if (s->char2b)
+ if (s->cmp == NULL
+ && (s->first_glyph->type == CHAR_GLYPH
+ || s->first_glyph->type == COMPOSITE_GLYPH))
{
struct font_metrics metrics;
- if (s->first_glyph->type == CHAR_GLYPH && !s->font_not_found_p)
- {
- font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
- s->left_overhang = -metrics.lbearing;
- s->right_overhang
- = metrics.rbearing > metrics.width
- ? metrics.rbearing - metrics.width : 0;
- }
- else if (s->first_glyph->type == COMPOSITE_GLYPH)
- {
- Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
- composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
- s->right_overhang = (metrics.rbearing > metrics.width
- ? metrics.rbearing - metrics.width : 0);
- s->left_overhang = metrics.lbearing < 0 ? -metrics.lbearing : 0;
- }
+ if (s->first_glyph->type == CHAR_GLYPH)
+ {
+ struct font *font = s->font;
+ font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
+ }
+ else
+ {
+ Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
+
+ composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
+ }
+ s->right_overhang = (metrics.rbearing > metrics.width
+ ? metrics.rbearing - metrics.width : 0);
+ s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
}
- else
+ else if (s->cmp)
{
- s->left_overhang = 0;
-#ifdef NS_IMPL_GNUSTEP
- if (EQ (font->driver->type, Qns))
- s->right_overhang = ((struct nsfont_info *)font)->ital ?
- FONT_HEIGHT (font) * 0.2 : 0;
- else
-#endif
- s->right_overhang = 0;
+ s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
+ s->left_overhang = - s->cmp->lbearing;
}
}
struct frame *f = WINDOW_XFRAME (w);
struct glyph *phys_cursor_glyph;
struct glyph *cursor_glyph;
- struct face *face;
- NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
/* If cursor is out of bounds, don't draw garbage. This can happen
in mini-buffer windows when switching between echo area glyphs
and mini-buffer. */
- NSTRACE ("ns_draw_window_cursor");
+ NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)",
+ on_p, cursor_type);
if (!on_p)
return;
if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
{
+ NSTRACE_MSG ("No phys cursor glyph was found!");
+
if (glyph_row->exact_window_width_line_p
&& w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
{
return;
}
- /* We draw the cursor (with NSRectFill), then draw the glyph on top
- (other terminals do it the other way round). We must set
- w->phys_cursor_width to the cursor width. For bar cursors, that
- is CURSOR_WIDTH; for box cursors, it is the glyph width. */
get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
/* The above get_phys_cursor_geometry call set w->phys_cursor_width
/* Prevent the cursor from being drawn outside the text area. */
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
- ns_focus (f, &r, 1);
+ ns_focus (f, NULL, 0);
- face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
- if (face && NS_FACE_BACKGROUND (face)
- == ns_index_color (FRAME_CURSOR_COLOR (f), f))
- {
- [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
- hollow_color = FRAME_CURSOR_COLOR (f);
- }
- else
- [FRAME_CURSOR_COLOR (f) set];
+ NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
+ [ctx saveGraphicsState];
+#ifdef NS_IMPL_GNUSTEP
+ GSRectClipList (ctx, &r, 1);
+#else
+ NSRectClip (r);
+#endif
+
+ [FRAME_CURSOR_COLOR (f) set];
switch (cursor_type)
{
case NO_CURSOR:
break;
case FILLED_BOX_CURSOR:
- NSRectFill (r);
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
break;
case HOLLOW_BOX_CURSOR:
- NSRectFill (r);
- [hollow_color set];
- NSRectFill (NSInsetRect (r, 1, 1));
- [FRAME_CURSOR_COLOR (f) set];
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT);
+ [NSBezierPath strokeRect: r];
break;
case HBAR_CURSOR:
NSRectFill (r);
NSRectFill (s);
break;
}
- ns_unfocus (f);
- /* Draw the character under the cursor. Other terms only draw
- the character on top of box cursors, so do the same here. */
- if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR)
- draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ [ctx restoreGraphicsState];
+ ns_unfocus (f);
}
if (s->for_overlaps)
return;
+ if (s->hl == DRAW_CURSOR)
+ [FRAME_BACKGROUND_COLOR (s->f) set];
+ else if (face->underline_defaulted_p)
+ [defaultCol set];
+ else
+ [ns_lookup_indexed_color (face->underline_color, s->f) set];
+
/* Do underline. */
if (face->underline)
{
if (s->face->underline == FACE_UNDER_WAVE)
{
- if (face->underline_defaulted_p)
- [defaultCol set];
- else
- [ns_lookup_indexed_color (face->underline_color, s->f) set];
-
ns_draw_underwave (s, width, x);
}
else if (s->face->underline == FACE_UNDER_LINE)
s->underline_position = position;
r = NSMakeRect (x, s->ybase + position, width, thickness);
-
- if (face->underline_defaulted_p)
- [defaultCol set];
- else
- [ns_lookup_indexed_color (face->underline_color, s->f) set];
NSRectFill (r);
}
}
{
NSRect r;
r = NSMakeRect (x, s->y, width, 1);
-
- if (face->overline_color_defaulted_p)
- [defaultCol set];
- else
- [ns_lookup_indexed_color (face->overline_color, s->f) set];
NSRectFill (r);
}
dy = lrint ((glyph_height - h) / 2);
r = NSMakeRect (x, glyph_y + dy, width, 1);
- if (face->strike_through_color_defaulted_p)
- [defaultCol set];
- else
- [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
NSRectFill (r);
}
}
struct glyph *last_glyph;
NSRect r;
int hthickness, vthickness;
- struct face *face;
-
- if (s->hl == DRAW_MOUSE_FACE)
- {
- face = FACE_FROM_ID_OR_NULL (s->f,
- MOUSE_HL_INFO (s->f)->mouse_face_face_id);
- if (!face)
- face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
- }
- else
- face = s->face;
+ struct face *face = s->face;
vthickness = face->box_vertical_line_width;
hthickness = face->box_horizontal_line_width;
|| FONT_TOO_HIGH (s->font)
|| s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
{
- struct face *face;
- if (s->hl == DRAW_MOUSE_FACE)
- {
- face
- = FACE_FROM_ID_OR_NULL (s->f,
- MOUSE_HL_INFO (s->f)->mouse_face_face_id);
- if (!face)
- face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
- }
- else
- face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ struct face *face = s->face;
if (!face->stipple)
- [(NS_FACE_BACKGROUND (face) != 0
- ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
- : FRAME_BACKGROUND_COLOR (s->f)) set];
+ {
+ if (s->hl != DRAW_CURSOR)
+ [(NS_FACE_BACKGROUND (face) != 0
+ ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
+ : FRAME_BACKGROUND_COLOR (s->f)) set];
+ else
+ [FRAME_CURSOR_COLOR (s->f) set];
+ }
else
{
struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
[[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
}
- if (s->hl != DRAW_CURSOR)
- {
- NSRect r = NSMakeRect (s->x, s->y + box_line_width,
- s->background_width,
- s->height-2*box_line_width);
- NSRectFill (r);
- }
+ NSRect r = NSMakeRect (s->x, s->y + box_line_width,
+ s->background_width,
+ s->height-2*box_line_width);
+ NSRectFill (r);
s->background_filled_p = 1;
}
int th;
char raised_p;
NSRect br;
- struct face *face;
+ struct face *face = s->face;
NSColor *tdCol;
NSTRACE ("ns_dumpglyphs_image");
/* Draw BG: if we need larger area than image itself cleared, do that,
otherwise, since we composite the image under NS (instead of mucking
with its background color), we must clear just the image area. */
- if (s->hl == DRAW_MOUSE_FACE)
- {
- face = FACE_FROM_ID_OR_NULL (s->f,
- MOUSE_HL_INFO (s->f)->mouse_face_face_id);
- if (!face)
- face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
- }
- else
- face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
[ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
if (s->hl == DRAW_CURSOR)
{
- [FRAME_CURSOR_COLOR (s->f) set];
- if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
+ [FRAME_CURSOR_COLOR (s->f) set];
tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
- else
- /* Currently on NS img->mask is always 0. Since
- get_window_cursor_type specifies a hollow box cursor when on
- a non-masked image we never reach this clause. But we put it
- in, in anticipation of better support for image masks on
- NS. */
- tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
}
else
{
static void
ns_dumpglyphs_stretch (struct glyph_string *s)
{
- NSRect r[2];
NSRect glyphRect;
- int n;
- struct face *face;
+ struct face *face = s->face;
NSColor *fgCol, *bgCol;
if (!s->background_filled_p)
{
- n = ns_get_glyph_string_clip_rect (s, r);
- ns_focus (s->f, r, n);
- if (s->hl == DRAW_MOUSE_FACE)
- {
- face = FACE_FROM_ID_OR_NULL (s->f,
- MOUSE_HL_INFO (s->f)->mouse_face_face_id);
- if (!face)
- face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
- }
- else
- face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ face = s->face;
bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
- glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
-
- [bgCol set];
-
- /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
- overwriting cursor (usually when cursor on a tab) */
if (s->hl == DRAW_CURSOR)
- {
- CGFloat x, width;
+ {
+ fgCol = bgCol;
+ bgCol = FRAME_CURSOR_COLOR (s->f);
+ }
- /* FIXME: This looks like it will only work for left to
- right languages. */
- x = NSMinX (glyphRect);
- width = s->w->phys_cursor_width;
- glyphRect.size.width -= width;
- glyphRect.origin.x += width;
+ glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
- NSRectFill (glyphRect);
+ [bgCol set];
- /* Draw overlining, etc. on the cursor. */
- if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
- ns_draw_text_decoration (s, face, bgCol, width, x);
- else
- ns_draw_text_decoration (s, face, fgCol, width, x);
- }
- else
- {
- NSRectFill (glyphRect);
- }
+ NSRectFill (glyphRect);
/* Draw overlining, etc. on the stretch glyph (or the part
of the stretch glyph after the cursor). */
ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect),
NSMinX (glyphRect));
- ns_unfocus (s->f);
s->background_filled_p = 1;
}
}
static void
ns_draw_glyph_string_foreground (struct glyph_string *s)
{
- int x, flags;
+ int x;
struct font *font = s->font;
/* If first glyph of S has a left box line, start drawing the text
else
x = s->x;
- flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
- (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
- (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
- NS_DUMPGLYPH_NORMAL));
-
font->driver->draw
(s, s->cmp_from, s->nchars, x, s->ybase,
- (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
- || flags == NS_DUMPGLYPH_MOUSEFACE);
+ !s->for_overlaps && !s->background_filled_p);
}
struct font *font = s->face->font;
if (! font) font = FRAME_FONT (s->f);
- NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
+ NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl);
- if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
+ if (s->next && s->right_overhang && !s->for_overlaps)
{
int width;
struct glyph_string *next;
box_drawn_p = 1;
}
+ n = ns_get_glyph_string_clip_rect (s, r);
+
+ if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
+ && !s->clip_tail
+ && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
+ || (s->next && s->next->hl != s->hl && s->right_overhang)))
+ r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height));
+
+ ns_focus (s->f, r, n);
+
switch (s->first_glyph->type)
{
case IMAGE_GLYPH:
- n = ns_get_glyph_string_clip_rect (s, r);
- ns_focus (s->f, r, n);
ns_dumpglyphs_image (s, r[0]);
- ns_unfocus (s->f);
break;
case XWIDGET_GLYPH:
case CHAR_GLYPH:
case COMPOSITE_GLYPH:
- n = ns_get_glyph_string_clip_rect (s, r);
- ns_focus (s->f, r, n);
-
- if (s->for_overlaps || (s->cmp_from > 0
- && ! s->first_glyph->u.cmp.automatic))
- s->background_filled_p = 1;
- else
- ns_maybe_dumpglyphs_background
- (s, s->first_glyph->type == COMPOSITE_GLYPH);
-
- if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
- {
- unsigned long tmp = NS_FACE_BACKGROUND (s->face);
- NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
- NS_FACE_FOREGROUND (s->face) = tmp;
- }
-
{
- BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
+ BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
+ if (s->for_overlaps || (isComposite
+ && (s->cmp_from > 0
+ && ! s->first_glyph->u.cmp.automatic)))
+ s->background_filled_p = 1;
+ else
+ ns_maybe_dumpglyphs_background
+ (s, s->first_glyph->type == COMPOSITE_GLYPH);
- if (isComposite)
- ns_draw_composite_glyph_string_foreground (s);
- else
- ns_draw_glyph_string_foreground (s);
- }
+ if (isComposite)
+ ns_draw_composite_glyph_string_foreground (s);
+ else
+ ns_draw_glyph_string_foreground (s);
- {
- NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
- ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
- s->f)
- : FRAME_FOREGROUND_COLOR (s->f));
- [col set];
-
- /* Draw underline, overline, strike-through. */
- ns_draw_text_decoration (s, s->face, col, s->width, s->x);
+ {
+ NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
+ ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
+ s->f)
+ : FRAME_FOREGROUND_COLOR (s->f));
+ [col set];
+
+ /* Draw underline, overline, strike-through. */
+ ns_draw_text_decoration (s, s->face, col, s->width, s->x);
+ }
}
- if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
- {
- unsigned long tmp = NS_FACE_BACKGROUND (s->face);
- NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
- NS_FACE_FOREGROUND (s->face) = tmp;
- }
-
- ns_unfocus (s->f);
break;
case GLYPHLESS_GLYPH:
- n = ns_get_glyph_string_clip_rect (s, r);
- ns_focus (s->f, r, n);
-
if (s->for_overlaps || (s->cmp_from > 0
&& ! s->first_glyph->u.cmp.automatic))
s->background_filled_p = 1;
/* ... */
/* Not yet implemented. */
/* ... */
- ns_unfocus (s->f);
break;
default:
/* Draw box if not done already. */
if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
+ ns_dumpglyphs_box_or_relief (s);
+
+ ns_unfocus (s->f);
+
+ /* Draw surrounding overhangs. */
+ if (s->prev)
{
- n = ns_get_glyph_string_clip_rect (s, r);
- ns_focus (s->f, r, n);
- ns_dumpglyphs_box_or_relief (s);
+ ns_focus (s->f, NULL, 0);
+ struct glyph_string *prev;
+
+ for (prev = s->prev; prev; prev = prev->prev)
+ if (prev->hl != s->hl
+ && prev->x + prev->width + prev->right_overhang > s->x)
+ {
+ /* As prev was drawn while clipped to its own area, we
+ must draw the right_overhang part using s->hl now. */
+ enum draw_glyphs_face save = prev->hl;
+ struct face *save_face = prev->face;
+
+ prev->face = s->face;
+ NSRect r = NSMakeRect (s->x, s->y, s->width, s->height);
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ NSRectClip (r);
+#ifdef NS_IMPL_GNUSTEP
+ DPSgsave ([NSGraphicsContext currentContext]);
+ DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y,
+ s->width, s->height);
+#endif
+ prev->num_clips = 1;
+ prev->hl = s->hl;
+ if (prev->first_glyph->type == CHAR_GLYPH)
+ ns_draw_glyph_string_foreground (prev);
+ else
+ ns_draw_composite_glyph_string_foreground (prev);
+#ifdef NS_IMPL_GNUSTEP
+ DPSgrestore ([NSGraphicsContext currentContext]);
+#endif
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+ prev->hl = save;
+ prev->face = save_face;
+ prev->num_clips = 0;
+ }
ns_unfocus (s->f);
}
+ if (s->next)
+ {
+ ns_focus (s->f, NULL, 0);
+ struct glyph_string *next;
+
+ for (next = s->next; next; next = next->next)
+ if (next->hl != s->hl
+ && next->x - next->left_overhang < s->x + s->width)
+ {
+ /* As next will be drawn while clipped to its own area,
+ we must draw the left_overhang part using s->hl now. */
+ enum draw_glyphs_face save = next->hl;
+ struct face *save_face = next->face;
+
+ next->hl = s->hl;
+ next->face = s->face;
+ NSRect r = NSMakeRect (s->x, s->y, s->width, s->height);
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ NSRectClip (r);
+#ifdef NS_IMPL_GNUSTEP
+ DPSgsave ([NSGraphicsContext currentContext]);
+ DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y,
+ s->width, s->height);
+#endif
+ next->num_clips = 1;
+ if (next->first_glyph->type == CHAR_GLYPH)
+ ns_draw_glyph_string_foreground (next);
+ else
+ ns_draw_composite_glyph_string_foreground (next);
+#ifdef NS_IMPL_GNUSTEP
+ DPSgrestore ([NSGraphicsContext currentContext]);
+#endif
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+ next->hl = save;
+ next->num_clips = 0;
+ next->face = save_face;
+ next->clip_head = next;
+ next->background_filled_p = 0;
+ }
+ ns_unfocus (s->f);
+ }
s->num_clips = 0;
}