1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
22 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
37 #include "character.h"
40 #define NSFONT_TRACE 0
42 extern Lisp_Object Qns;
43 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
44 static Lisp_Object Qapple, Qroman, Qmedium;
45 extern Lisp_Object ns_expand_space;
46 extern Lisp_Object Qappend;
47 extern int ns_antialias_text, ns_use_qd_smoothing;
48 extern float ns_antialias_threshold;
49 extern int ns_tmp_flags;
50 extern struct nsfont_info *ns_tmp_font;
52 /* font glyph and metrics caching functions, implemented at end */
53 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
55 static void ns_glyph_metrics (struct nsfont_info *font_info,
59 /* ==========================================================================
63 ========================================================================== */
66 /* Replace spaces w/another character so emacs core font parsing routines
69 nsfont_escape_name (char *name)
71 int i =0, len =strlen (name);
78 /* Reconstruct spaces in a font family name passed through emacs. */
80 nsfont_unescape_name (char *name)
82 int i =0, len =strlen (name);
89 /* Extract family name from a font spec. */
91 nsfont_get_family (Lisp_Object font_spec)
93 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
98 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
100 nsfont_unescape_name (tmp);
101 /* PENDING: this seems to be needed only for font names that are
102 hard-coded into emacs, like 'helvetica' for splash screen */
104 tmp[0] = toupper (tmp[0]);
105 family = [NSString stringWithUTF8String: tmp];
112 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
113 /* PENDING (20080601): The font backend's strategy for handling font
114 styles continues to evolve. When/if this stabilizes, we
115 can change the code here to be more sophisticated and accurate.
116 For now, we rely on "normal/plain" style being numeric 100. */
117 #define STYLE_REF 100
119 nsfont_spec_to_traits (Lisp_Object font_spec)
121 unsigned int traits = 0;
124 n = FONT_WEIGHT_NUMERIC (font_spec);
126 traits |= (n > STYLE_REF) ? NSBoldFontMask : NSUnboldFontMask;
128 n = FONT_SLANT_NUMERIC (font_spec);
130 traits |= (n > STYLE_REF) ? NSItalicFontMask : NSUnitalicFontMask;
132 n = FONT_WIDTH_NUMERIC (font_spec);
135 if (n < STYLE_REF - 10)
136 traits |= NSCondensedFontMask;
137 else if (n > STYLE_REF + 10)
138 traits |= NSExpandedFontMask;
141 /*fprintf (stderr, " returning traits = %u\n", traits); */
146 /* Converts NSArray of PS name, non-family part, weight, and traits to a
147 font backend font-entity. */
149 nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
151 Lisp_Object font_entity = font_make_entity ();
152 unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
153 /* NSString *psName = [famMember objectAtIndex: 0]; */
154 NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
155 char *escapedFamily = [family UTF8String];
157 nsfont_escape_name (escapedFamily);
158 [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
159 range: NSMakeRange (0, [suffix length])];
161 ASET (font_entity, FONT_TYPE_INDEX, Qns);
162 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
163 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
164 ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
165 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
167 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
168 traits & NSBoldFontMask ? Qbold : Qmedium);
169 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
170 traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
171 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
172 traits & NSCondensedFontMask ? Qcondensed :
173 traits & NSExpandedFontMask ? Qexpanded : Qnormal);
175 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
176 ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
177 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
181 fprintf (stderr, "created font_entity:\n ");
182 debug_print (font_entity);
190 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
192 nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
195 for (i =0; i<sizeof (unsigned int)*8; i++)
197 d += (traits1 & 0x1) ^ (traits2 & 0x1);
205 /* Default font entity based on Monaco. */
207 nsfont_fallback_entity ()
209 NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
210 NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
211 [NSNumber numberWithUnsignedInt: 5],
212 [NSNumber numberWithUnsignedInt: 0], nil];
213 return nsfont_fmember_to_entity (family, famMemberSpec);
217 /* ==========================================================================
219 Font driver implementation
221 ========================================================================== */
223 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
224 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
225 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
226 static Lisp_Object nsfont_list_family (Lisp_Object frame);
227 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
229 static void nsfont_close (FRAME_PTR f, struct font *font);
230 static int nsfont_has_char (Lisp_Object entity, int c);
231 static unsigned int nsfont_encode_char (struct font *font, int c);
232 static int nsfont_text_extents (struct font *font, unsigned int *code,
233 int nglyphs, struct font_metrics *metrics);
234 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
235 int with_background);
237 struct font_driver nsfont_driver =
239 (Lisp_Object) NULL, /* Qns */
240 1, /* case sensitive */
245 NULL, /*free_entity */
248 NULL, /* prepare_face */
249 NULL, /* done_face */
254 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
255 anchor_point, otf_capability, otf_driver,
256 start_for_frame, end_for_frame, shape */
260 /* Return a cache of font-entities on FRAME. The cache must be a
261 cons whose cdr part is the actual cache area. */
263 nsfont_get_cache (FRAME_PTR frame)
265 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
266 return (dpyinfo->name_list_element);
270 /* List fonts exactly matching with FONT_SPEC on FRAME. The value
271 is a vector of font-entities. This is the sole API that
272 allocates font-entities. */
274 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
276 Lisp_Object list = Qnil;
280 NSEnumerator *famEnum;
281 NSFontManager *fontMgr;
282 unsigned int traits = nsfont_spec_to_traits (font_spec);
286 fprintf (stderr, "nsfont: list for fontspec:\n ");
287 debug_print (font_spec);
290 /* if has non-unicode registry, give up */
291 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
292 if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
295 fontMgr = [NSFontManager sharedFontManager];
297 family = nsfont_get_family (font_spec);
300 families = [NSArray arrayWithObject: family];
302 families = [fontMgr availableFontFamilies];
304 for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
307 NSArray *fmember, *firstMember = nil;
308 unsigned int mtraits;
309 BOOL foundItal = NO || (traits & NSUnitalicFontMask);
310 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
312 /* LastResort is special: not a family but a font name only */
313 if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
315 famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
316 @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
317 [NSNumber numberWithUnsignedInt: 0], nil]];
321 /* fmember = [postscriptName style weight traits] */
322 fm = [famMembers objectEnumerator];
323 while (fmember = [fm nextObject])
325 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
326 if ((mtraits & traits) == traits)
328 list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
329 if (mtraits & NSItalicFontMask)
331 if (firstMember == nil)
332 firstMember = fmember;
335 if (foundItal == NO && firstMember != nil)
337 /* no italic member found; add a synthesized one */
338 NSMutableArray *smember = [firstMember mutableCopy];
339 [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
340 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
341 mtraits |= NSItalicFontMask;
342 [smember replaceObjectAtIndex: 3
343 withObject: [NSNumber numberWithUnsignedInt: mtraits]];
344 /*NSLog (@"-- adding synthItal member: %@", smember); */
345 list = Fcons (nsfont_fmember_to_entity (family, smember), list);
351 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
353 return (NILP (list) ? Qnil : Fvconcat (1, &list));/* Qnil was null_vector */
357 /* Return a font entity most closely maching with FONT_SPEC on
358 FRAME. The closeness is determined by the font backend, thus
359 `face-font-selection-order' is ignored here. */
361 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
363 long traits = nsfont_spec_to_traits (font_spec);
364 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
370 fprintf (stderr, "nsfont: match for fontspec:\n ");
371 debug_print (font_spec);
374 /* if has non-unicode registry, just return fallback */
376 tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
378 fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
380 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
381 if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
382 return nsfont_fallback_entity ();
384 family = nsfont_get_family (font_spec);
388 /* try to find close font in family */
389 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
390 NSEnumerator *fm = [famMembers objectEnumerator];
392 int minDist = sizeof (unsigned int) * 8 + 1;
393 int bestMatchIdx = -1;
396 for (i =0; fmember = [fm nextObject]; i++)
398 unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
399 int dist = nsfont_trait_distance ((mtraits & traits), traits);
406 if (bestMatchIdx != -1)
407 return nsfont_fmember_to_entity
408 (family, [famMembers objectAtIndex: bestMatchIdx]);
411 /* no family that had members was given; find any font matching traits */
413 NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
414 if (fontNames && [fontNames count] > 0)
416 NSString *fontName = [fontNames objectAtIndex: 0];
417 /*PENDING: is there a more efficient way to get family name? */
418 NSFont *font = [NSFont fontWithName: fontName size: 0];
421 /* now need to get suffix part of name.. */
422 NSString *family = [font familyName];
423 NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
426 while (fmember = [fm nextObject])
428 unsigned int mtraits =
429 [[fmember objectAtIndex: 3] unsignedIntValue];
430 if (mtraits & traits == traits)
431 return nsfont_fmember_to_entity (family, fmember);
437 /* if we get here, return the fallback */
439 fprintf (stderr, " *** returning fallback\n");
441 return nsfont_fallback_entity ();
445 /* List available families. The value is a list of family names
448 nsfont_list_family (Lisp_Object frame)
450 Lisp_Object list = Qnil;
451 NSEnumerator *families =
452 [[[NSFontManager sharedFontManager] availableFontFamilies]
455 while (family = [families nextObject])
456 list = Fcons (intern ([family UTF8String]), list);
457 /*PENDING: escape the name? */
460 fprintf (stderr, "nsfont: list families returning %d entries\n",
461 XINT (Flength (list)));
467 /* utility: get width of a char c in screen font sfont */
469 nsfont_char_width (NSFont *sfont, int c)
472 NSString *cstr = [NSString stringWithFormat: @"%c", c];
474 NSGlyph glyph = [sfont glyphWithName: cstr];
477 float w = [sfont advancementForGlyph: glyph].width;
482 w = [sfont widthOfString: cstr];
487 /* Open a font specified by FONT_ENTITY on frame F. If the font is
488 scalable, open it with PIXEL_SIZE. */
490 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
493 struct nsfont_info *font_info;
495 unsigned int traits = nsfont_spec_to_traits (font_entity);
496 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
498 NSFont *nsfont, *sfont;
501 Lisp_Object font_object;
505 static NSMutableDictionary *fontCache = nil;
507 /* 2008/03/08: The same font may end up being requested for different
508 entities, due to small differences in numeric values or other issues,
509 or for different copies of the same entity. Therefore we cache to
510 avoid creating multiple struct font objects (with metrics cache, etc.)
511 for the same NSFont object.
512 2008/06/01: This is still an issue, but after font backend refactoring
513 caching will be more difficult, needs to be reworked before enabling. */
514 if (fontCache == nil)
515 fontCache = [[NSMutableDictionary alloc] init];
518 font_object = font_make_object (VECSIZE (struct nsfont_info), font_entity,
520 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
521 font = (struct font *)font_info;
523 return NULL; /*PENDING: this copies w32, but causes a segfault */
527 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
528 debug_print (font_entity);
533 /* try to get it out of frame params */
534 Lisp_Object tem = get_frame_param (f, Qfontsize);
535 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
538 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
539 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
541 family = nsfont_get_family (font_entity);
544 fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\n",
545 [family UTF8String], traits, traits & NSBoldFontMask);
548 /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
549 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
550 nsfont = [fontMgr fontWithFamily: family
551 traits: traits weight: fixLeopardBug
553 /* if didn't find, try synthetic italic */
554 if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
556 nsfont = [fontMgr fontWithFamily: family
557 traits: traits & ~NSItalicFontMask
558 weight: fixLeopardBug size: pixel_size];
561 /* LastResort not really a family */
562 if (nsfont == nil && [@"LastResort" isEqualToString: family])
564 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
570 message_with_string ("*** Warning: font in family '%s' not found",
571 build_string ([family UTF8String]), 1);
572 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
575 fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
582 NSNumber *cached = [fontCache objectForKey: nsfont];
583 if (cached != nil && !synthItal)
585 fprintf (stderr, "*** CACHE HIT!\n");
586 struct font_info *existing =
587 (struct nsfont_info *)[cached unsignedLongValue];
594 setObject: [NSNumber numberWithUnsignedLong:
595 (unsigned long)font_info]
601 font_info->glyphs = (unsigned short *)
602 xmalloc (0x100 * sizeof (unsigned short *));
603 font_info->metrics = (struct font_metrics *)
604 xmalloc (0x100 * sizeof (struct font_metrics *));
605 if (!font_info->glyphs || !font_info->metrics)
607 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
608 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
614 sfont = [nsfont screenFont];
618 /* non-metric backend font struct fields */
619 font = (struct font *) font_info;
620 font->pixel_size = [sfont pointSize];
621 font->driver = &nsfont_driver;
622 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
623 font->encoding_charset = -1;
624 font->repertory_charset = -1;
625 font->default_ascent = 0;
626 font->vertical_centering = 0;
627 font->baseline_offset = 0;
628 font->relative_compose = 0;
629 font->font_encoder = NULL;
631 /*PENDING: does anything care about this? */
632 font->props[FONT_FORMAT_INDEX] = Qns;
633 font->props[FONT_FILE_INDEX] = Qnil;
636 double expand, shrink, hshrink;
637 float full_height, min_height, hd;
638 const char *fontName = [[nsfont fontName] UTF8String];
639 int len = strlen (fontName);
641 #ifdef NS_IMPL_GNUSTEP
642 font_info->nsfont = sfont;
644 font_info->nsfont = nsfont;
646 [font_info->nsfont retain];
648 /* set up ns_font (defined in nsgui.h) */
649 font_info->name = (char *)xmalloc (strlen (fontName)+1);
650 bcopy (fontName, font_info->name, strlen (fontName)+1);
651 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
653 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
655 /* Metrics etc.; some fonts return an unusually large max advance, so we
656 only use it for fonts that have wide characters. */
657 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
658 [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
660 brect = [sfont boundingRectForFont];
661 full_height = brect.size.height;
662 min_height = [sfont ascender] - [sfont descender];
663 hd = full_height - min_height;
665 if (!NUMBERP (ns_expand_space))
666 error ("No expand space defined");
668 /* ns_expand_space = 0.0 is use standard height; less shrink, more expand */
669 expand = XFLOATINT (ns_expand_space) + 0.5;
674 hshrink = 1 + expand / 2.0;
678 shrink = hshrink = 1.0;
680 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
681 font_info->underwidth = [sfont underlineThickness];
682 font_info->size = font->pixel_size;
683 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
686 font_info->max_bounds.ascent =
687 lrint (hshrink * [sfont ascender] + expand * hd/2);
688 font_info->max_bounds.descent =
689 -lrint (hshrink* [sfont descender] - expand*hd/2);
691 font_info->max_bounds.ascent + font_info->max_bounds.descent;
692 font_info->max_bounds.width = lrint (font_info->width);
693 font_info->max_bounds.lbearing = lrint (brect.origin.x);
694 font_info->max_bounds.rbearing =
695 lrint (brect.size.width - font_info->width);
696 /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
699 /* set up synthItal and the CG font */
700 font_info->synthItal = synthItal;
702 ATSFontRef atsFont = ATSFontFindFromPostScriptName
703 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
705 if (atsFont == kATSFontRefUnspecified)
707 /* see if we can get it by dropping italic (then synthesizing) */
708 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
709 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
710 fontName], kATSOptionFlagsDefault);
711 if (atsFont != kATSFontRefUnspecified)
712 font_info->synthItal = YES;
715 /* last resort fallback */
716 atsFont = ATSFontFindFromPostScriptName
717 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
720 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
724 /* set up metrics portion of font struct */
725 font->ascent = [sfont ascender];
726 font->descent = -[sfont descender];
727 font->min_width = [sfont widthOfString: @"|"]; /* PENDING */
728 font->space_width = lrint (nsfont_char_width (sfont, ' '));
729 font->average_width = lrint (font_info->width);
730 font->max_width = lrint (font_info->max_bounds.width);
731 font->height = lrint (font_info->height);
732 font->underline_position = lrint (font_info->underpos);
733 font->underline_thickness = lrint (font_info->underwidth);
735 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
736 font->props[FONT_FULLNAME_INDEX] =
737 make_unibyte_string (font_info->name, strlen (font_info->name));
745 /* Close FONT on frame F. */
747 nsfont_close (FRAME_PTR f, struct font *font)
749 struct nsfont_info *font_info = (struct nsfont_info *)font;
752 /* PENDING: this occurs apparently due to same failure to detect same font
753 that causes need for cache in nsfont_open ()
754 (came after unicode-2 -> trunk) */
758 for (i =0; i<0x100; i++)
760 if (font_info->glyphs[i])
761 xfree (font_info->glyphs[i]);
762 if (font_info->metrics[i])
763 xfree (font_info->metrics[i]);
765 [font_info->nsfont release];
767 CGFontRelease (font_info->cgfont);
769 xfree (font_info->name);
774 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
775 return 1. If not, return 0. If a font must be opened to check
778 nsfont_has_char (Lisp_Object entity, int c)
784 /* Return a glyph code of FONT for character C (Unicode code point).
785 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
787 nsfont_encode_char (struct font *font, int c)
789 struct nsfont_info *font_info = (struct nsfont_info *)font;
790 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
794 return FONT_INVALID_CODE;
796 /* did we already cache this block? */
797 if (!font_info->glyphs[high])
798 ns_uni_to_glyphs (font_info, high);
800 g = font_info->glyphs[high][low];
801 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
802 return g == 0xFFFF ? FONT_INVALID_CODE : g;
806 /* Perform the size computation of glyphs of FONT and fill in members
807 of METRICS. The glyphs are specified by their glyph codes in
808 CODE (length NGLYPHS). */
810 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
811 struct font_metrics *metrics)
813 struct nsfont_info *font_info = (struct nsfont_info *)font;
814 struct font_metrics *pcm;
815 unsigned char high, low;
819 bzero (metrics, sizeof (struct font_metrics));
821 for (i =0; i<nglyphs; i++)
823 /* get metrics for this glyph, filling cache if need be */
824 /* PENDING: get metrics for whole string from an NSLayoutManager
826 high = (code[i] & 0xFF00) >> 8;
827 low = code[i] & 0x00FF;
828 if (!font_info->metrics[high])
829 ns_glyph_metrics (font_info, high);
830 pcm = &(font_info->metrics[high][low]);
832 if (metrics->lbearing > totalWidth + pcm->lbearing)
833 metrics->lbearing = totalWidth + pcm->lbearing;
834 if (metrics->rbearing < totalWidth + pcm->rbearing)
835 metrics->rbearing = totalWidth + pcm->rbearing;
836 if (metrics->ascent < pcm->ascent)
837 metrics->ascent = pcm->ascent;
838 if (metrics->descent < pcm->descent)
839 metrics->descent = pcm->descent;
841 totalWidth += pcm->width;
844 metrics->width = totalWidth;
846 return totalWidth; /* not specified in doc, but xfont.c does it */
850 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
851 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
852 is nonzero, fill the background in advance. It is assured that
853 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
855 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
857 /* NOTE: focus and clip must be set
858 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
860 static char cbuf[1024];
862 #ifdef NS_IMPL_GNUSTEP
863 static float advances[1024];
864 float *adv = advances;
866 static CGSize advances[1024];
867 CGSize *adv = advances;
871 struct nsfont_info *font = ns_tmp_font;
872 NSColor *col, *bgCol;
873 unsigned short *t = s->char2b;
876 /* Select face based on input flags */
877 switch (ns_tmp_flags)
879 case NS_DUMPGLYPH_CURSOR:
882 case NS_DUMPGLYPH_MOUSEFACE:
883 face = FACE_FROM_ID (s->f,
884 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
886 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
893 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
894 r.origin.x += abs (s->face->box_line_width);
897 r.size.height = FONT_HEIGHT (font);
899 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
900 NS to render the string, it will come out differently from the individual
901 character widths added up because of layout processing. */
904 int cwidth, twidth = 0;
906 char isComposite = 0; /* s->first_glyph->type == COMPOSITE_GLYPH; */
907 /* PENDING: composition: no vertical displacement is considered. */
908 t+= s->gidx; /* advance into composition */
909 for (i =0; i<s->nchars - s->gidx; i++, t++)
911 hi = (*t & 0xFF00) >> 8;
915 cwidth = s->cmp->offsets[s->gidx++ * 2] - twidth;
919 if (!font->metrics[hi]) /*PENDING: why/how can we need this now? */
920 ns_glyph_metrics (font, hi);
921 cwidth = font->metrics[hi][lo].width;
924 #ifdef NS_IMPL_GNUSTEP
926 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
928 (*adv++).width = cwidth;
931 len = adv - advances;
932 r.size.width = twidth;
936 /* fill background if requested */
940 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
941 int mbox_line_width = max (s->face->box_line_width, 0);
943 if (s->row->full_width_p)
945 if (br.origin.x <= fibw + 1 + mbox_line_width)
947 br.size.width += br.origin.x - mbox_line_width;
948 br.origin.x = mbox_line_width;
950 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
952 br.size.width += fibw;
954 if (s->face->box == FACE_NO_BOX)
956 /* expand unboxed top row over internal border */
957 if (br.origin.y <= fibw + 1 + mbox_line_width)
959 br.size.height += br.origin.y;
965 int correction = abs (s->face->box_line_width)+1;
966 br.origin.y += correction;
967 br.size.height -= 2*correction;
968 br.origin.x += correction;
969 br.size.width -= 2*correction;
972 if (!s->face->stipple)
973 [(NS_FACE_BACKGROUND (face) != nil
974 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
975 : FRAME_BACKGROUND_COLOR (s->f)) set];
978 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
979 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
985 /* set up for character rendering */
986 r.origin.y += font->voffset + (s->height - font->height)/2;
988 col = (NS_FACE_FOREGROUND (face) != nil
989 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
990 : FRAME_FOREGROUND_COLOR (s->f));
991 /*PENDING: find another way to pass this */
992 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
993 : (NS_FACE_BACKGROUND (face) != nil
994 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
995 : FRAME_BACKGROUND_COLOR (s->f)));
997 /* render under GNUstep using DPS */
998 #ifdef NS_IMPL_GNUSTEP
1000 NSGraphicsContext *context = GSCurrentContext ();
1005 /* do erase if "foreground" mode */
1009 DPSmoveto (context, r.origin.x, r.origin.y);
1010 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1011 DPSxshow (context, cbuf, advances, len);
1012 DPSstroke (context);
1014 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1018 if (face->underline_p)
1020 if (face->underline_color != nil)
1021 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1024 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1025 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1026 if (face->underline_color != nil)
1032 /* draw with DPSxshow () */
1033 DPSmoveto (context, r.origin.x, r.origin.y);
1034 DPSxshow (context, cbuf, advances, len);
1035 DPSstroke (context);
1037 DPSgrestore (context);
1041 #else /* NS_IMPL_COCOA */
1043 CGContextRef gcontext =
1044 [[NSGraphicsContext currentContext] graphicsPort];
1045 static CGAffineTransform fliptf;
1046 static BOOL firstTime = YES;
1051 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1054 CGContextSaveGState (gcontext);
1056 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1058 CGContextSetFont (gcontext, font->cgfont);
1059 CGContextSetFontSize (gcontext, font->size);
1060 if (ns_antialias_text == NO || font->size <= ns_antialias_threshold)
1061 CGContextSetShouldAntialias (gcontext, 0);
1063 CGContextSetShouldAntialias (gcontext, 1);
1064 if (ns_use_qd_smoothing)
1065 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1067 CGContextSetTextMatrix (gcontext, fliptf);
1071 /* foreground drawing; erase first to avoid overstrike */
1073 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1074 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1075 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1076 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1079 if (face->underline_p)
1081 if (face->underline_color != nil)
1082 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1085 CGContextBeginPath (gcontext);
1086 CGContextMoveToPoint (gcontext,
1087 r.origin.x, r.origin.y + font->underpos);
1088 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1089 r.origin.y + font->underpos);
1090 CGContextStrokePath (gcontext);
1091 if (face->underline_color != nil)
1097 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1098 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->gidx,
1101 if (face->overstrike)
1103 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1104 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->gidx,
1108 CGContextRestoreGState (gcontext);
1111 #endif /* NS_IMPL_COCOA */
1116 /* Auto-creates a fontset built around the font in font_object,
1117 by creating an attributed string with characters from each
1118 script, then requesting the NS text system to fix attributes
1120 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1122 Lisp_Object script, famAndReg;
1123 struct nsfont_info *font_info =
1124 (struct nsfont_info *)XFONT_OBJECT (font_object);
1126 /* NS text system (and char buf) init */
1127 static NSTextStorage *store;
1128 static NSLayoutManager *layout;
1129 static NSRange range;
1130 static NSMutableDictionary *attribs;
1131 static Lisp_Object *scripts;
1132 static int nscripts;
1133 static int *scriptsNchars;
1134 static BOOL firstTime = YES;
1135 Lisp_Object regString = build_string ("iso10646-1");
1138 if (firstTime == YES)
1140 nscripts = XINT (Flength (Vscript_representative_chars));
1141 scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1142 unsigned char *buf = malloc (4*nscripts*sizeof (char));
1143 Lisp_Object scriptsChars = Vscript_representative_chars;
1144 unsigned char *tpos = buf;
1146 scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1148 for (i =0; i<nscripts; i++)
1150 Lisp_Object sChars = XCAR (scriptsChars);
1151 Lisp_Object chars = XCDR (sChars);
1152 unsigned int ch, c =0;
1153 scripts[i] = XCAR (sChars);
1155 while (CONSP (chars))
1157 ch = XUINT (XCAR (chars));
1158 chars = XCDR (chars);
1159 CHAR_STRING_ADVANCE (ch, tpos);
1162 scriptsNchars[i] = c;
1164 scriptsChars = XCDR (scriptsChars);
1168 store = [[NSTextStorage alloc] init];
1169 layout = [[NSLayoutManager alloc] init];
1170 [store addLayoutManager: layout];
1173 [store beginEditing];
1174 [[store mutableString] appendString:
1175 [NSString stringWithUTF8String: buf]];
1179 range = NSMakeRange (0, [store length]);
1181 attribs = [[NSMutableDictionary alloc] init];
1186 [store beginEditing];
1187 [store removeAttribute: NSFontAttributeName range: range];
1188 [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1189 [store addAttributes: attribs range: range];
1194 NSMutableDictionary *map =
1195 [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1196 NSEnumerator *fonts;
1197 NSFont *cfont = nil, *tfont;
1201 for (i =0; i<nscripts; i++)
1203 [map removeAllObjects];
1204 for (j =0; j<scriptsNchars[i]; j++)
1206 cfont = [store attribute: NSFontAttributeName atIndex: idx++
1207 effectiveRange: NULL];
1208 n = [map objectForKey: cfont];
1210 n = [NSNumber numberWithInt: 1];
1212 n = [NSNumber numberWithInt: [n intValue] + 1];
1213 [map setObject: n forKey: cfont];
1216 /* majority rules */
1218 fonts = [map keyEnumerator];
1219 while (tfont = [fonts nextObject])
1221 n = [map objectForKey: tfont];
1222 if ([n intValue] > max)
1231 char *family = [[cfont familyName] UTF8String];
1232 Lisp_Object famAndReg;
1234 nsfont_escape_name (family);
1235 famAndReg = Fcons (build_string (family), regString);
1238 fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1239 font_info->name, family,
1240 SDATA (SYMBOL_NAME (scripts[i])));
1242 Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1246 fprintf (stderr, "%s fontset: none found for script '%s'\n",
1247 font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1249 } /* for i = script */
1255 /* ==========================================================================
1257 Font glyph and metrics caching functions
1259 ========================================================================== */
1261 /* Find and cache corresponding glyph codes for unicode values in given
1262 hi-byte block of 256. */
1264 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1266 #ifdef NS_IMPL_COCOA
1267 static EmacsGlyphStorage *glyphStorage;
1268 static char firstTime = 1;
1270 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1271 unsigned int i, g, idx;
1272 unsigned short *glyphs;
1275 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1280 #ifdef NS_IMPL_COCOA
1284 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1288 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1289 if (!unichars || !(font_info->glyphs[block]))
1292 /* create a string containing all unicode characters in this block */
1293 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1294 if (idx < 0xD800 || idx > 0xDFFF)
1297 unichars[i] = 0xFEFF;
1298 unichars[0x100] = 0;
1301 #ifdef NS_IMPL_COCOA
1302 NSString *allChars = [[NSString alloc]
1303 initWithCharactersNoCopy: unichars
1306 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1307 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1308 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1309 unsigned int gInd =0, cInd =0;
1311 [glyphStorage setString: allChars font: font_info->nsfont];
1312 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1313 desiredNumberOfCharacters: glyphStorage->maxChar
1314 glyphIndex: &gInd characterIndex: &cInd];
1316 glyphs = font_info->glyphs[block];
1317 for (i =0; i<0x100; i++, glyphs++)
1319 #ifdef NS_IMPL_GNUSTEP
1322 g = glyphStorage->cglyphs[i];
1323 /*PENDING: is this a good check? maybe need to use coveredChars.. */
1325 g = 0xFFFF; /* hopefully unused... */
1330 #ifdef NS_IMPL_COCOA
1340 /* Determine and cache metrics for corresponding glyph codes in given
1341 hi-byte block of 256. */
1343 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1346 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1348 struct font_metrics *metrics;
1351 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1354 #ifdef NS_IMPL_GNUSTEP
1355 /* not implemented yet (as of startup 0.18), so punt */
1357 numGlyphs = 0x10000;
1361 sfont = [font_info->nsfont screenFont];
1363 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1364 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1365 if (!(font_info->metrics[block]))
1368 metrics = font_info->metrics[block];
1369 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1372 NSRect r = [sfont boundingRectForGlyph: g];
1374 #ifdef NS_IMPL_GNUSTEP
1377 NSString *s = [NSString stringWithFormat: @"%c", g];
1378 w = [sfont widthOfString: s];
1381 w = [sfont advancementForGlyph: g].width;
1384 metrics->width = lrint (w);
1387 rb = r.size.width - w;
1389 metrics->lbearing = round (lb);
1390 if (font_info->ital)
1391 rb += 0.22 * font_info->height;
1392 metrics->rbearing = lrint (w + rb);
1394 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1395 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1396 metrics->ascent = r.size.height - metrics->descent;
1397 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1403 #ifdef NS_IMPL_COCOA
1404 /* helper for font glyph setup */
1405 @implementation EmacsGlyphStorage
1409 return [self initWithCapacity: 1024];
1412 - initWithCapacity: (unsigned long) c
1414 self = [super init];
1417 dict = [NSMutableDictionary new];
1418 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1431 - (void) setString: (NSString *)str font: (NSFont *)font
1433 [dict setObject: font forKey: NSFontAttributeName];
1434 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1435 maxChar = [str length];
1439 /* NSGlyphStorage protocol */
1440 - (unsigned int)layoutOptions
1445 - (NSAttributedString *)attributedString
1450 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1451 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1452 characterIndex: (unsigned int)charIndex
1454 len = glyphIndex+length;
1455 for (i =glyphIndex; i<len; i++)
1456 cglyphs[i] = glyphs[i-glyphIndex];
1461 - (void)setIntAttribute: (int)attributeTag value: (int)val
1462 forGlyphAtIndex: (unsigned)glyphIndex
1468 #endif /* NS_IMPL_COCOA */
1473 dump_glyphstring (struct glyph_string *s)
1477 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1478 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1479 s->row->overlapping_p, s->background_filled_p);
1480 for (i =0; i<s->nchars; i++)
1481 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1482 fprintf (stderr, "\n");
1490 nsfont_driver.type = Qns;
1491 register_font_driver (&nsfont_driver, NULL);
1492 DEFSYM (Qapple, "apple");
1493 DEFSYM (Qroman, "roman");
1494 DEFSYM (Qmedium, "medium");
1497 /* arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae
1498 (do not change this comment) */