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 of the License, or
10 (at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>.
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
26 #include "dispextern.h"
27 #include "composite.h"
28 #include "blockinput.h"
35 #include "character.h"
38 #define NSFONT_TRACE 0
40 extern Lisp_Object Qns;
41 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
42 static Lisp_Object Qapple, Qroman, Qmedium;
43 extern Lisp_Object ns_expand_space;
44 extern Lisp_Object Qappend;
45 extern int ns_antialias_text, ns_use_qd_smoothing;
46 extern float ns_antialias_threshold;
47 extern int ns_tmp_flags;
48 extern struct nsfont_info *ns_tmp_font;
50 /* font glyph and metrics caching functions, implemented at end */
51 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
53 static void ns_glyph_metrics (struct nsfont_info *font_info,
57 /* ==========================================================================
61 ========================================================================== */
64 /* Replace spaces w/another character so emacs core font parsing routines
67 nsfont_escape_name (char *name)
69 int i =0, len =strlen (name);
76 /* Reconstruct spaces in a font family name passed through emacs. */
78 nsfont_unescape_name (char *name)
80 int i =0, len =strlen (name);
87 /* Extract family name from a font spec. */
89 nsfont_get_family (Lisp_Object font_spec)
91 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
96 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
98 nsfont_unescape_name (tmp);
99 /* TODO: this seems to be needed only for font names that are
100 hard-coded into emacs, like 'helvetica' for splash screen */
102 tmp[0] = toupper (tmp[0]);
103 family = [NSString stringWithUTF8String: tmp];
110 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
111 /* TODO (20080601): The font backend's strategy for handling font
112 styles continues to evolve. When/if this stabilizes, we
113 can change the code here to be more sophisticated and accurate.
114 For now, we rely on "normal/plain" style being numeric 100. */
115 #define STYLE_REF 100
117 nsfont_spec_to_traits (Lisp_Object font_spec)
119 unsigned int traits = 0;
122 n = FONT_WEIGHT_NUMERIC (font_spec);
124 traits |= (n > STYLE_REF) ? NSBoldFontMask : NSUnboldFontMask;
126 n = FONT_SLANT_NUMERIC (font_spec);
128 traits |= (n > STYLE_REF) ? NSItalicFontMask : NSUnitalicFontMask;
130 n = FONT_WIDTH_NUMERIC (font_spec);
133 if (n < STYLE_REF - 10)
134 traits |= NSCondensedFontMask;
135 else if (n > STYLE_REF + 10)
136 traits |= NSExpandedFontMask;
139 /*fprintf (stderr, " returning traits = %u\n", traits); */
144 /* Converts NSArray of PS name, non-family part, weight, and traits to a
145 font backend font-entity. */
147 nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
149 Lisp_Object font_entity = font_make_entity ();
150 unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
151 /* NSString *psName = [famMember objectAtIndex: 0]; */
152 NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
153 char *escapedFamily = strdup ([family UTF8String]);
155 nsfont_escape_name (escapedFamily);
156 [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
157 range: NSMakeRange (0, [suffix length])];
159 ASET (font_entity, FONT_TYPE_INDEX, Qns);
160 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
161 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
162 ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
163 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
165 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
166 traits & NSBoldFontMask ? Qbold : Qmedium);
167 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
168 traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
169 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
170 traits & NSCondensedFontMask ? Qcondensed :
171 traits & NSExpandedFontMask ? Qexpanded : Qnormal);
173 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
174 ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
175 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
179 fprintf (stderr, "created font_entity:\n ");
180 debug_print (font_entity);
184 free (escapedFamily);
189 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
191 nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
194 for (i =0; i<sizeof (unsigned int)*8; i++)
196 d += (traits1 & 0x1) ^ (traits2 & 0x1);
204 /* Default font entity based on Monaco. */
206 nsfont_fallback_entity ()
208 NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
209 NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
210 [NSNumber numberWithUnsignedInt: 5],
211 [NSNumber numberWithUnsignedInt: 0], nil];
212 return nsfont_fmember_to_entity (family, famMemberSpec);
216 /* ==========================================================================
218 Font driver implementation
220 ========================================================================== */
222 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
223 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
224 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
225 static Lisp_Object nsfont_list_family (Lisp_Object frame);
226 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
228 static void nsfont_close (FRAME_PTR f, struct font *font);
229 static int nsfont_has_char (Lisp_Object entity, int c);
230 static unsigned int nsfont_encode_char (struct font *font, int c);
231 static int nsfont_text_extents (struct font *font, unsigned int *code,
232 int nglyphs, struct font_metrics *metrics);
233 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
234 int with_background);
236 struct font_driver nsfont_driver =
239 1, /* case sensitive */
244 NULL, /*free_entity */
247 NULL, /* prepare_face */
248 NULL, /* done_face */
253 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
254 anchor_point, otf_capability, otf_driver,
255 start_for_frame, end_for_frame, shape */
259 /* Return a cache of font-entities on FRAME. The cache must be a
260 cons whose cdr part is the actual cache area. */
262 nsfont_get_cache (FRAME_PTR frame)
264 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
265 return (dpyinfo->name_list_element);
269 /* List fonts exactly matching with FONT_SPEC on FRAME. The value
270 is a vector of font-entities. This is the sole API that
271 allocates font-entities. */
273 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
275 Lisp_Object list = Qnil;
279 NSEnumerator *famEnum;
280 NSFontManager *fontMgr;
281 unsigned int traits = nsfont_spec_to_traits (font_spec);
285 fprintf (stderr, "nsfont: list for fontspec:\n ");
286 debug_print (font_spec);
289 /* if has non-unicode registry, give up */
290 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
291 if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
294 fontMgr = [NSFontManager sharedFontManager];
296 family = nsfont_get_family (font_spec);
299 families = [NSArray arrayWithObject: family];
301 families = [fontMgr availableFontFamilies];
303 for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
306 NSArray *fmember, *firstMember = nil;
307 unsigned int mtraits;
308 BOOL foundItal = NO || (traits & NSUnitalicFontMask);
309 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
311 /* LastResort is special: not a family but a font name only */
312 if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
314 famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
315 @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
316 [NSNumber numberWithUnsignedInt: 0], nil]];
320 /* fmember = [postscriptName style weight traits] */
321 fm = [famMembers objectEnumerator];
322 while (fmember = [fm nextObject])
324 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
325 if ((mtraits & traits) == traits)
327 list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
328 if (mtraits & NSItalicFontMask)
330 if (firstMember == nil)
331 firstMember = fmember;
334 if (foundItal == NO && firstMember != nil)
336 /* no italic member found; add a synthesized one */
337 NSMutableArray *smember = [firstMember mutableCopy];
338 [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
339 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
340 mtraits |= NSItalicFontMask;
341 [smember replaceObjectAtIndex: 3
342 withObject: [NSNumber numberWithUnsignedInt: mtraits]];
343 /*NSLog (@"-- adding synthItal member: %@", smember); */
344 list = Fcons (nsfont_fmember_to_entity (family, smember), list);
350 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
352 return (NILP (list) ? Qnil : Fvconcat (1, &list));/* Qnil was null_vector */
356 /* Return a font entity most closely maching with FONT_SPEC on
357 FRAME. The closeness is determined by the font backend, thus
358 `face-font-selection-order' is ignored here. */
360 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
362 long traits = nsfont_spec_to_traits (font_spec);
363 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
369 fprintf (stderr, "nsfont: match for fontspec:\n ");
370 debug_print (font_spec);
373 /* if has non-unicode registry, just return fallback */
375 tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
377 fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
379 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
380 if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
381 return nsfont_fallback_entity ();
383 family = nsfont_get_family (font_spec);
387 /* try to find close font in family */
388 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
389 NSEnumerator *fm = [famMembers objectEnumerator];
391 int minDist = sizeof (unsigned int) * 8 + 1;
392 int bestMatchIdx = -1;
395 for (i =0; fmember = [fm nextObject]; i++)
397 unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
398 int dist = nsfont_trait_distance ((mtraits & traits), traits);
405 if (bestMatchIdx != -1)
406 return nsfont_fmember_to_entity
407 (family, [famMembers objectAtIndex: bestMatchIdx]);
410 /* no family that had members was given; find any font matching traits */
412 NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
413 if (fontNames && [fontNames count] > 0)
415 NSString *fontName = [fontNames objectAtIndex: 0];
416 /* XXX: is there a more efficient way to get family name? */
417 NSFont *font = [NSFont fontWithName: fontName size: 0];
420 /* now need to get suffix part of name.. */
421 NSString *family = [font familyName];
422 NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
425 while (fmember = [fm nextObject])
427 unsigned int mtraits =
428 [[fmember objectAtIndex: 3] unsignedIntValue];
429 if (mtraits & traits == traits)
430 return nsfont_fmember_to_entity (family, fmember);
436 /* if we get here, return the fallback */
438 fprintf (stderr, " *** returning fallback\n");
440 return nsfont_fallback_entity ();
444 /* List available families. The value is a list of family names
447 nsfont_list_family (Lisp_Object frame)
449 Lisp_Object list = Qnil;
450 NSEnumerator *families =
451 [[[NSFontManager sharedFontManager] availableFontFamilies]
454 while (family = [families nextObject])
455 list = Fcons (intern ([family UTF8String]), list);
456 /* FIXME: escape the name? */
459 fprintf (stderr, "nsfont: list families returning %d entries\n",
460 XINT (Flength (list)));
466 /* utility: get width of a char c in screen font sfont */
468 nsfont_char_width (NSFont *sfont, int c)
471 NSString *cstr = [NSString stringWithFormat: @"%c", c];
473 NSGlyph glyph = [sfont glyphWithName: cstr];
476 float w = [sfont advancementForGlyph: glyph].width;
481 w = [sfont widthOfString: cstr];
486 /* Open a font specified by FONT_ENTITY on frame F. If the font is
487 scalable, open it with PIXEL_SIZE. */
489 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
492 struct nsfont_info *font_info;
494 unsigned int traits = nsfont_spec_to_traits (font_entity);
495 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
497 NSFont *nsfont, *sfont;
500 Lisp_Object font_object;
504 static NSMutableDictionary *fontCache = nil;
506 /* 2008/03/08: The same font may end up being requested for different
507 entities, due to small differences in numeric values or other issues,
508 or for different copies of the same entity. Therefore we cache to
509 avoid creating multiple struct font objects (with metrics cache, etc.)
510 for the same NSFont object.
511 2008/06/01: This is still an issue, but after font backend refactoring
512 caching will be more difficult, needs to be reworked before enabling. */
513 if (fontCache == nil)
514 fontCache = [[NSMutableDictionary alloc] init];
517 font_object = font_make_object (VECSIZE (struct nsfont_info), font_entity,
519 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
520 font = (struct font *)font_info;
522 return Qnil; /* FIXME: this copies w32, but causes a segfault */
526 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
527 debug_print (font_entity);
532 /* try to get it out of frame params */
533 Lisp_Object tem = get_frame_param (f, Qfontsize);
534 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
537 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
538 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
540 family = nsfont_get_family (font_entity);
543 fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\n",
544 [family UTF8String], traits, traits & NSBoldFontMask);
547 /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
548 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
549 nsfont = [fontMgr fontWithFamily: family
550 traits: traits weight: fixLeopardBug
552 /* if didn't find, try synthetic italic */
553 if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
555 nsfont = [fontMgr fontWithFamily: family
556 traits: traits & ~NSItalicFontMask
557 weight: fixLeopardBug size: pixel_size];
560 /* LastResort not really a family */
561 if (nsfont == nil && [@"LastResort" isEqualToString: family])
563 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
569 message_with_string ("*** Warning: font in family '%s' not found",
570 build_string ([family UTF8String]), 1);
571 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
574 fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
581 NSNumber *cached = [fontCache objectForKey: nsfont];
582 if (cached != nil && !synthItal)
584 fprintf (stderr, "*** CACHE HIT!\n");
585 struct font_info *existing =
586 (struct nsfont_info *)[cached unsignedLongValue];
593 setObject: [NSNumber numberWithUnsignedLong:
594 (unsigned long)font_info]
600 font_info->glyphs = (unsigned short **)
601 xmalloc (0x100 * sizeof (unsigned short *));
602 font_info->metrics = (struct font_metrics **)
603 xmalloc (0x100 * sizeof (struct font_metrics *));
604 if (!font_info->glyphs || !font_info->metrics)
606 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
607 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
613 sfont = [nsfont screenFont];
617 /* non-metric backend font struct fields */
618 font = (struct font *) font_info;
619 font->pixel_size = [sfont pointSize];
620 font->driver = &nsfont_driver;
621 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
622 font->encoding_charset = -1;
623 font->repertory_charset = -1;
624 font->default_ascent = 0;
625 font->vertical_centering = 0;
626 font->baseline_offset = 0;
627 font->relative_compose = 0;
628 font->font_encoder = NULL;
630 /* TODO: does anything care about this? */
631 font->props[FONT_FORMAT_INDEX] = Qns;
632 font->props[FONT_FILE_INDEX] = Qnil;
635 double expand, shrink, hshrink;
636 float full_height, min_height, hd;
637 const char *fontName = [[nsfont fontName] UTF8String];
638 int len = strlen (fontName);
640 #ifdef NS_IMPL_GNUSTEP
641 font_info->nsfont = sfont;
643 font_info->nsfont = nsfont;
645 [font_info->nsfont retain];
647 /* set up ns_font (defined in nsgui.h) */
648 font_info->name = (char *)xmalloc (strlen (fontName)+1);
649 bcopy (fontName, font_info->name, strlen (fontName)+1);
650 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
652 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
654 /* Metrics etc.; some fonts return an unusually large max advance, so we
655 only use it for fonts that have wide characters. */
656 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
657 [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
659 brect = [sfont boundingRectForFont];
660 full_height = brect.size.height;
661 min_height = [sfont ascender] - [sfont descender];
662 hd = full_height - min_height;
664 if (!NUMBERP (ns_expand_space))
665 error ("No expand space defined");
667 /* ns_expand_space = 0.0 is use standard height; less shrink, more expand */
668 expand = XFLOATINT (ns_expand_space) + 0.5;
673 hshrink = 1 + expand / 2.0;
677 shrink = hshrink = 1.0;
679 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
680 font_info->underwidth = [sfont underlineThickness];
681 font_info->size = font->pixel_size;
682 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
685 font_info->max_bounds.ascent =
686 lrint (hshrink * [sfont ascender] + expand * hd/2);
687 font_info->max_bounds.descent =
688 -lrint (hshrink* [sfont descender] - expand*hd/2);
690 font_info->max_bounds.ascent + font_info->max_bounds.descent;
691 font_info->max_bounds.width = lrint (font_info->width);
692 font_info->max_bounds.lbearing = lrint (brect.origin.x);
693 font_info->max_bounds.rbearing =
694 lrint (brect.size.width - font_info->width);
695 /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
698 /* set up synthItal and the CG font */
699 font_info->synthItal = synthItal;
701 ATSFontRef atsFont = ATSFontFindFromPostScriptName
702 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
704 if (atsFont == kATSFontRefUnspecified)
706 /* see if we can get it by dropping italic (then synthesizing) */
707 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
708 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
709 fontName], kATSOptionFlagsDefault);
710 if (atsFont != kATSFontRefUnspecified)
711 font_info->synthItal = YES;
714 /* last resort fallback */
715 atsFont = ATSFontFindFromPostScriptName
716 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
719 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
723 /* set up metrics portion of font struct */
724 font->ascent = [sfont ascender];
725 font->descent = -[sfont descender];
726 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
727 font->space_width = lrint (nsfont_char_width (sfont, ' '));
728 font->average_width = lrint (font_info->width);
729 font->max_width = lrint (font_info->max_bounds.width);
730 font->height = lrint (font_info->height);
731 font->underline_position = lrint (font_info->underpos);
732 font->underline_thickness = lrint (font_info->underwidth);
734 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
735 font->props[FONT_FULLNAME_INDEX] =
736 make_unibyte_string (font_info->name, strlen (font_info->name));
744 /* Close FONT on frame F. */
746 nsfont_close (FRAME_PTR f, struct font *font)
748 struct nsfont_info *font_info = (struct nsfont_info *)font;
751 /* FIXME: this occurs apparently due to same failure to detect same font
752 that causes need for cache in nsfont_open ()
753 (came after unicode-2 -> trunk) */
757 for (i =0; i<0x100; i++)
759 if (font_info->glyphs[i])
760 xfree (font_info->glyphs[i]);
761 if (font_info->metrics[i])
762 xfree (font_info->metrics[i]);
764 [font_info->nsfont release];
766 CGFontRelease (font_info->cgfont);
768 xfree (font_info->name);
773 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
774 return 1. If not, return 0. If a font must be opened to check
777 nsfont_has_char (Lisp_Object entity, int c)
783 /* Return a glyph code of FONT for character C (Unicode code point).
784 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
786 nsfont_encode_char (struct font *font, int c)
788 struct nsfont_info *font_info = (struct nsfont_info *)font;
789 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
793 return FONT_INVALID_CODE;
795 /* did we already cache this block? */
796 if (!font_info->glyphs[high])
797 ns_uni_to_glyphs (font_info, high);
799 g = font_info->glyphs[high][low];
800 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
801 return g == 0xFFFF ? FONT_INVALID_CODE : g;
805 /* Perform the size computation of glyphs of FONT and fill in members
806 of METRICS. The glyphs are specified by their glyph codes in
807 CODE (length NGLYPHS). */
809 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
810 struct font_metrics *metrics)
812 struct nsfont_info *font_info = (struct nsfont_info *)font;
813 struct font_metrics *pcm;
814 unsigned char high, low;
818 bzero (metrics, sizeof (struct font_metrics));
820 for (i =0; i<nglyphs; i++)
822 /* get metrics for this glyph, filling cache if need be */
823 /* TODO: get metrics for whole string from an NSLayoutManager
825 high = (code[i] & 0xFF00) >> 8;
826 low = code[i] & 0x00FF;
827 if (!font_info->metrics[high])
828 ns_glyph_metrics (font_info, high);
829 pcm = &(font_info->metrics[high][low]);
831 if (metrics->lbearing > totalWidth + pcm->lbearing)
832 metrics->lbearing = totalWidth + pcm->lbearing;
833 if (metrics->rbearing < totalWidth + pcm->rbearing)
834 metrics->rbearing = totalWidth + pcm->rbearing;
835 if (metrics->ascent < pcm->ascent)
836 metrics->ascent = pcm->ascent;
837 if (metrics->descent < pcm->descent)
838 metrics->descent = pcm->descent;
840 totalWidth += pcm->width;
843 metrics->width = totalWidth;
845 return totalWidth; /* not specified in doc, but xfont.c does it */
849 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
850 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
851 is nonzero, fill the background in advance. It is assured that
852 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
854 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
856 /* NOTE: focus and clip must be set
857 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
859 static char cbuf[1024];
861 #ifdef NS_IMPL_GNUSTEP
862 static float advances[1024];
863 float *adv = advances;
865 static CGSize advances[1024];
866 CGSize *adv = advances;
870 struct nsfont_info *font = ns_tmp_font;
871 NSColor *col, *bgCol;
872 unsigned short *t = s->char2b;
875 /* Select face based on input flags */
876 switch (ns_tmp_flags)
878 case NS_DUMPGLYPH_CURSOR:
881 case NS_DUMPGLYPH_MOUSEFACE:
882 face = FACE_FROM_ID (s->f,
883 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
885 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
892 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
893 r.origin.x += abs (s->face->box_line_width);
896 r.size.height = FONT_HEIGHT (font);
898 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
899 NS to render the string, it will come out differently from the individual
900 character widths added up because of layout processing. */
903 int cwidth, twidth = 0;
905 char isComposite = 0; /* s->first_glyph->type == COMPOSITE_GLYPH; */
906 /* FIXME: composition: no vertical displacement is considered. */
907 t+= s->cmp_from; /* advance into composition */
908 for (i =0; i<s->nchars - s->cmp_from; i++, t++)
910 hi = (*t & 0xFF00) >> 8;
914 cwidth = s->cmp->offsets[s->cmp_from++ * 2] - twidth;
918 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
919 ns_glyph_metrics (font, hi);
920 cwidth = font->metrics[hi][lo].width;
923 #ifdef NS_IMPL_GNUSTEP
925 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
927 (*adv++).width = cwidth;
930 len = adv - advances;
931 r.size.width = twidth;
935 /* fill background if requested */
939 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
940 int mbox_line_width = max (s->face->box_line_width, 0);
942 if (s->row->full_width_p)
944 if (br.origin.x <= fibw + 1 + mbox_line_width)
946 br.size.width += br.origin.x - mbox_line_width;
947 br.origin.x = mbox_line_width;
949 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
951 br.size.width += fibw;
953 if (s->face->box == FACE_NO_BOX)
955 /* expand unboxed top row over internal border */
956 if (br.origin.y <= fibw + 1 + mbox_line_width)
958 br.size.height += br.origin.y;
964 int correction = abs (s->face->box_line_width)+1;
965 br.origin.y += correction;
966 br.size.height -= 2*correction;
967 br.origin.x += correction;
968 br.size.width -= 2*correction;
971 if (!s->face->stipple)
972 [(NS_FACE_BACKGROUND (face) != 0
973 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
974 : FRAME_BACKGROUND_COLOR (s->f)) set];
977 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
978 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
984 /* set up for character rendering */
985 r.origin.y += font->voffset + (s->height - font->height)/2;
987 col = (NS_FACE_FOREGROUND (face) != 0
988 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
989 : FRAME_FOREGROUND_COLOR (s->f));
990 /* FIXME: find another way to pass this */
991 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
992 : (NS_FACE_BACKGROUND (face) != 0
993 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
994 : FRAME_BACKGROUND_COLOR (s->f)));
996 /* render under GNUstep using DPS */
997 #ifdef NS_IMPL_GNUSTEP
999 NSGraphicsContext *context = GSCurrentContext ();
1004 /* do erase if "foreground" mode */
1008 DPSmoveto (context, r.origin.x, r.origin.y);
1009 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1010 DPSxshow (context, cbuf, advances, len);
1011 DPSstroke (context);
1013 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1017 if (face->underline_p)
1019 if (face->underline_color != 0)
1020 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1023 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1024 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1025 if (face->underline_color != 0)
1031 /* draw with DPSxshow () */
1032 DPSmoveto (context, r.origin.x, r.origin.y);
1033 DPSxshow (context, cbuf, advances, len);
1034 DPSstroke (context);
1036 DPSgrestore (context);
1040 #else /* NS_IMPL_COCOA */
1042 CGContextRef gcontext =
1043 [[NSGraphicsContext currentContext] graphicsPort];
1044 static CGAffineTransform fliptf;
1045 static BOOL firstTime = YES;
1050 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1053 CGContextSaveGState (gcontext);
1055 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1057 CGContextSetFont (gcontext, font->cgfont);
1058 CGContextSetFontSize (gcontext, font->size);
1059 if (ns_antialias_text == NO || font->size <= ns_antialias_threshold)
1060 CGContextSetShouldAntialias (gcontext, 0);
1062 CGContextSetShouldAntialias (gcontext, 1);
1063 if (EQ (ns_use_qd_smoothing, Qt))
1064 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1066 CGContextSetTextMatrix (gcontext, fliptf);
1070 /* foreground drawing; erase first to avoid overstrike */
1072 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1073 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1074 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1075 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1078 if (face->underline_p)
1080 if (face->underline_color != 0)
1081 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1084 CGContextBeginPath (gcontext);
1085 CGContextMoveToPoint (gcontext,
1086 r.origin.x, r.origin.y + font->underpos);
1087 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1088 r.origin.y + font->underpos);
1089 CGContextStrokePath (gcontext);
1090 if (face->underline_color != 0)
1096 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1097 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1100 if (face->overstrike)
1102 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1103 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1107 CGContextRestoreGState (gcontext);
1110 #endif /* NS_IMPL_COCOA */
1115 /* Auto-creates a fontset built around the font in font_object,
1116 by creating an attributed string with characters from each
1117 script, then requesting the NS text system to fix attributes
1119 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1121 Lisp_Object script, famAndReg;
1122 struct nsfont_info *font_info =
1123 (struct nsfont_info *)XFONT_OBJECT (font_object);
1125 /* NS text system (and char buf) init */
1126 static NSTextStorage *store;
1127 static NSLayoutManager *layout;
1128 static NSRange range;
1129 static NSMutableDictionary *attribs;
1130 static Lisp_Object *scripts;
1131 static int nscripts;
1132 static int *scriptsNchars;
1133 static BOOL firstTime = YES;
1134 Lisp_Object regString = build_string ("iso10646-1");
1137 if (firstTime == YES)
1139 nscripts = XINT (Flength (Vscript_representative_chars));
1140 scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1141 unsigned char *buf = malloc (4*nscripts*sizeof (char));
1142 Lisp_Object scriptsChars = Vscript_representative_chars;
1143 unsigned char *tpos = buf;
1145 scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1147 for (i =0; i<nscripts; i++)
1149 Lisp_Object sChars = XCAR (scriptsChars);
1150 Lisp_Object chars = XCDR (sChars);
1151 unsigned int ch, c =0;
1152 scripts[i] = XCAR (sChars);
1154 while (CONSP (chars))
1156 ch = XUINT (XCAR (chars));
1157 chars = XCDR (chars);
1158 CHAR_STRING_ADVANCE (ch, tpos);
1161 scriptsNchars[i] = c;
1163 scriptsChars = XCDR (scriptsChars);
1167 store = [[NSTextStorage alloc] init];
1168 layout = [[NSLayoutManager alloc] init];
1169 [store addLayoutManager: layout];
1172 [store beginEditing];
1173 [[store mutableString] appendString:
1174 [NSString stringWithUTF8String: buf]];
1178 range = NSMakeRange (0, [store length]);
1180 attribs = [[NSMutableDictionary alloc] init];
1185 [store beginEditing];
1186 [store removeAttribute: NSFontAttributeName range: range];
1187 [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1188 [store addAttributes: attribs range: range];
1193 NSMutableDictionary *map =
1194 [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1195 NSEnumerator *fonts;
1196 NSFont *cfont = nil, *tfont;
1200 for (i =0; i<nscripts; i++)
1202 [map removeAllObjects];
1203 for (j =0; j<scriptsNchars[i]; j++)
1205 cfont = [store attribute: NSFontAttributeName atIndex: idx++
1206 effectiveRange: NULL];
1207 n = [map objectForKey: cfont];
1209 n = [NSNumber numberWithInt: 1];
1211 n = [NSNumber numberWithInt: [n intValue] + 1];
1212 [map setObject: n forKey: cfont];
1215 /* majority rules */
1217 fonts = [map keyEnumerator];
1218 while (tfont = [fonts nextObject])
1220 n = [map objectForKey: tfont];
1221 if ([n intValue] > max)
1230 char *family = strdup([[cfont familyName] UTF8String]);
1231 Lisp_Object famAndReg;
1233 nsfont_escape_name (family);
1234 famAndReg = Fcons (build_string (family), regString);
1237 fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1238 font_info->name, family,
1239 SDATA (SYMBOL_NAME (scripts[i])));
1241 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 /* TODO: 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