1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006, 2007, 2008, 2009 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)
23 /* This should be the first include, as it may set up #defines affecting
24 interpretation of even the system includes. */
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 Qappend;
46 extern int ns_antialias_text, ns_use_qd_smoothing;
47 extern float ns_antialias_threshold;
48 extern int ns_tmp_flags;
49 extern struct nsfont_info *ns_tmp_font;
51 /* font glyph and metrics caching functions, implemented at end */
52 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
54 static void ns_glyph_metrics (struct nsfont_info *font_info,
58 /* ==========================================================================
62 ========================================================================== */
65 /* Replace spaces w/another character so emacs core font parsing routines
68 nsfont_escape_name (char *name)
70 int i =0, len =strlen (name);
77 /* Reconstruct spaces in a font family name passed through emacs. */
79 nsfont_unescape_name (char *name)
81 int i =0, len =strlen (name);
88 /* Extract family name from a font spec. */
90 nsfont_get_family (Lisp_Object font_spec)
92 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
97 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
99 nsfont_unescape_name (tmp);
100 /* TODO: this seems to be needed only for font names that are
101 hard-coded into emacs, like 'helvetica' for splash screen */
103 tmp[0] = toupper (tmp[0]);
104 family = [NSString stringWithUTF8String: tmp];
111 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
112 /* TODO (20080601): The font backend's strategy for handling font
113 styles continues to evolve. When/if this stabilizes, we
114 can change the code here to be more sophisticated and accurate.
115 For now, we rely on "normal/plain" style being numeric 100. */
116 #define STYLE_REF 100
118 nsfont_spec_to_traits (Lisp_Object font_spec)
120 unsigned int traits = 0;
123 n = FONT_WEIGHT_NUMERIC (font_spec);
125 traits |= (n > STYLE_REF) ? NSBoldFontMask
126 : (n < STYLE_REF) ? NSUnboldFontMask : 0;
128 n = FONT_SLANT_NUMERIC (font_spec);
130 traits |= (n > STYLE_REF) ? NSItalicFontMask
131 : (n < STYLE_REF) ? NSUnitalicFontMask : 0;
133 n = FONT_WIDTH_NUMERIC (font_spec);
135 traits |= (n > STYLE_REF + 10) ? NSExpandedFontMask
136 : (n < STYLE_REF - 10) ? NSExpandedFontMask : 0;
138 /*fprintf (stderr, " returning traits = %u\n", traits); */
143 /* Converts NSArray of PS name, non-family part, weight, and traits to a
144 font backend font-entity. */
146 nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
148 Lisp_Object font_entity = font_make_entity ();
149 unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
150 /* NSString *psName = [famMember objectAtIndex: 0]; */
151 NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
152 char *escapedFamily = strdup ([family UTF8String]);
154 nsfont_escape_name (escapedFamily);
155 [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
156 range: NSMakeRange (0, [suffix length])];
158 ASET (font_entity, FONT_TYPE_INDEX, Qns);
159 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
160 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
161 ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
162 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
164 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
165 traits & NSBoldFontMask ? Qbold : Qmedium);
166 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
167 traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
168 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
169 traits & NSCondensedFontMask ? Qcondensed :
170 traits & NSExpandedFontMask ? Qexpanded : Qnormal);
172 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
173 ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
174 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
178 fprintf (stderr, "created font_entity:\n ");
179 debug_print (font_entity);
183 free (escapedFamily);
188 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
190 nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
193 for (i = 0; i < sizeof (unsigned int) * 8; i++)
195 d += (traits1 & 0x1) ^ (traits2 & 0x1);
203 /* Default font entity based on Monaco. */
205 nsfont_fallback_entity ()
207 NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
208 NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
209 [NSNumber numberWithUnsignedInt: 5],
210 [NSNumber numberWithUnsignedInt: 0], nil];
211 return nsfont_fmember_to_entity (family, famMemberSpec);
215 /* ==========================================================================
217 Font driver implementation
219 ========================================================================== */
221 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
222 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
223 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
224 static Lisp_Object nsfont_list_family (Lisp_Object frame);
225 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
227 static void nsfont_close (FRAME_PTR f, struct font *font);
228 static int nsfont_has_char (Lisp_Object entity, int c);
229 static unsigned int nsfont_encode_char (struct font *font, int c);
230 static int nsfont_text_extents (struct font *font, unsigned int *code,
231 int nglyphs, struct font_metrics *metrics);
232 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
233 int with_background);
235 struct font_driver nsfont_driver =
238 1, /* case sensitive */
243 NULL, /*free_entity */
246 NULL, /* prepare_face */
247 NULL, /* done_face */
252 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
253 anchor_point, otf_capability, otf_driver,
254 start_for_frame, end_for_frame, shape */
258 /* Return a cache of font-entities on FRAME. The cache must be a
259 cons whose cdr part is the actual cache area. */
261 nsfont_get_cache (FRAME_PTR frame)
263 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
264 return (dpyinfo->name_list_element);
268 /* List fonts exactly matching with FONT_SPEC on FRAME. The value
269 is a **list** of font-entities. This is the sole API that
270 allocates font-entities. */
272 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
274 Lisp_Object list = Qnil;
278 NSEnumerator *famEnum;
279 NSFontManager *fontMgr;
280 unsigned int traits = nsfont_spec_to_traits (font_spec);
284 fprintf (stderr, "nsfont: list for fontspec:\n ");
285 debug_print (font_spec);
288 /* if has non-unicode registry, give up */
289 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
290 if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
293 fontMgr = [NSFontManager sharedFontManager];
295 family = nsfont_get_family (font_spec);
298 families = [NSArray arrayWithObject: family];
300 families = [fontMgr availableFontFamilies];
302 for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
305 NSArray *fmember, *firstMember = nil;
306 unsigned int mtraits;
307 BOOL foundItal = NO || (traits & NSUnitalicFontMask);
308 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
310 /* LastResort is special: not a family but a font name only */
311 if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
313 famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
314 @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
315 [NSNumber numberWithUnsignedInt: 0], nil]];
319 /* fmember = [postscriptName style weight traits] */
320 fm = [famMembers objectEnumerator];
321 while (fmember = [fm nextObject])
323 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
324 if ((mtraits & traits) == traits)
326 list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
327 if (mtraits & NSItalicFontMask)
329 if (firstMember == nil)
330 firstMember = fmember;
333 if (foundItal == NO && firstMember != nil)
335 /* no italic member found; add a synthesized one */
336 NSMutableArray *smember = [firstMember mutableCopy];
337 [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
338 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
339 mtraits |= NSItalicFontMask;
340 [smember replaceObjectAtIndex: 3
341 withObject: [NSNumber numberWithUnsignedInt: mtraits]];
342 /*NSLog (@"-- adding synthItal member: %@", smember); */
343 list = Fcons (nsfont_fmember_to_entity (family, smember), list);
349 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
355 /* Return a font entity most closely maching with FONT_SPEC on
356 FRAME. The closeness is determined by the font backend, thus
357 `face-font-selection-order' is ignored here. */
359 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
361 long traits = nsfont_spec_to_traits (font_spec);
362 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
368 fprintf (stderr, "nsfont: match for fontspec:\n ");
369 debug_print (font_spec);
372 /* if has non-unicode registry, just return fallback */
374 tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
376 fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
378 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
379 if (!NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
380 return nsfont_fallback_entity ();
382 family = nsfont_get_family (font_spec);
386 /* try to find close font in family */
387 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
388 NSEnumerator *fm = [famMembers objectEnumerator];
390 int minDist = sizeof (unsigned int) * 8 + 1;
391 int bestMatchIdx = -1;
394 for (i =0; fmember = [fm nextObject]; i++)
396 unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
397 int dist = nsfont_trait_distance ((mtraits & traits), traits);
404 if (bestMatchIdx != -1)
405 return nsfont_fmember_to_entity
406 (family, [famMembers objectAtIndex: bestMatchIdx]);
409 /* no family that had members was given; find any font matching traits */
411 NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
412 if (fontNames && [fontNames count] > 0)
414 NSString *fontName = [fontNames objectAtIndex: 0];
415 /* XXX: is there a more efficient way to get family name? */
416 NSFont *font = [NSFont fontWithName: fontName size: 0];
419 /* now need to get suffix part of name.. */
420 NSString *family = [font familyName];
421 NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
424 while (fmember = [fm nextObject])
426 unsigned int mtraits =
427 [[fmember objectAtIndex: 3] unsignedIntValue];
428 if (mtraits & traits == traits)
429 return nsfont_fmember_to_entity (family, fmember);
435 /* if we get here, return the fallback */
437 fprintf (stderr, " *** returning fallback\n");
439 return nsfont_fallback_entity ();
443 /* List available families. The value is a list of family names
446 nsfont_list_family (Lisp_Object frame)
448 Lisp_Object list = Qnil;
449 NSEnumerator *families =
450 [[[NSFontManager sharedFontManager] availableFontFamilies]
453 while (family = [families nextObject])
454 list = Fcons (intern ([family UTF8String]), list);
455 /* FIXME: escape the name? */
458 fprintf (stderr, "nsfont: list families returning %d entries\n",
459 XINT (Flength (list)));
465 /* utility: get width of a char c in screen font sfont */
467 nsfont_char_width (NSFont *sfont, int c)
470 NSString *cstr = [NSString stringWithFormat: @"%c", c];
472 NSGlyph glyph = [sfont glyphWithName: cstr];
475 float w = [sfont advancementForGlyph: glyph].width;
480 w = [sfont widthOfString: cstr];
485 /* Open a font specified by FONT_ENTITY on frame F. If the font is
486 scalable, open it with PIXEL_SIZE. */
488 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
491 struct nsfont_info *font_info;
493 unsigned int traits = nsfont_spec_to_traits (font_entity);
494 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
496 NSFont *nsfont, *sfont;
499 Lisp_Object font_object;
502 static NSMutableDictionary *fontCache = nil;
505 /* 2008/03/08: The same font may end up being requested for different
506 entities, due to small differences in numeric values or other issues,
507 or for different copies of the same entity. Therefore we cache to
508 avoid creating multiple struct font objects (with metrics cache, etc.)
509 for the same NSFont object.
510 2008/06/01: This is still an issue after font backend refactoring. */
511 if (fontCache == nil)
512 fontCache = [[NSMutableDictionary alloc] init];
516 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
517 debug_print (font_entity);
522 /* try to get it out of frame params */
523 Lisp_Object tem = get_frame_param (f, Qfontsize);
524 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
527 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
528 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
530 family = nsfont_get_family (font_entity);
533 fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\titalic = %d\n",
534 [family UTF8String], traits, traits & NSBoldFontMask,
535 traits & NSItalicFontMask);
538 /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
539 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
540 nsfont = [fontMgr fontWithFamily: family
541 traits: traits weight: fixLeopardBug
543 /* if didn't find, try synthetic italic */
544 if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
546 nsfont = [fontMgr fontWithFamily: family
547 traits: traits & ~NSItalicFontMask
548 weight: fixLeopardBug size: pixel_size];
551 /* LastResort not really a family */
552 if (nsfont == nil && [@"LastResort" isEqualToString: family])
554 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
560 message_with_string ("*** Warning: font in family '%s' not found",
561 build_string ([family UTF8String]), 1);
562 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
565 fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
571 NSLog (@"%@\n", nsfont);
573 /* Check the cache */
574 cached = [fontCache objectForKey: nsfont];
575 if (cached != nil && !synthItal)
578 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
579 // FIXME: Cast from (unsigned long) to Lisp_Object.
580 XHASH (font_object) = [cached unsignedLongValue];
585 font_object = font_make_object (VECSIZE (struct nsfont_info),
586 font_entity, pixel_size);
589 setObject: [NSNumber numberWithUnsignedLong:
590 (unsigned long) XHASH (font_object)]
594 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
595 font = (struct font *)font_info;
597 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
599 font_info->glyphs = (unsigned short **)
600 xmalloc (0x100 * sizeof (unsigned short *));
601 font_info->metrics = (struct font_metrics **)
602 xmalloc (0x100 * sizeof (struct font_metrics *));
603 if (!font_info->glyphs || !font_info->metrics)
605 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
606 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
611 sfont = [nsfont screenFont];
615 /* non-metric backend font struct fields */
616 font = (struct font *) font_info;
617 font->pixel_size = [sfont pointSize];
618 font->driver = &nsfont_driver;
619 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
620 font->encoding_charset = -1;
621 font->repertory_charset = -1;
622 font->default_ascent = 0;
623 font->vertical_centering = 0;
624 font->baseline_offset = 0;
625 font->relative_compose = 0;
626 font->font_encoder = NULL;
628 /* TODO: does anything care about this? */
629 font->props[FONT_FORMAT_INDEX] = Qns;
630 font->props[FONT_FILE_INDEX] = Qnil;
633 double expand, shrink, hshrink;
634 float full_height, min_height, hd;
635 const char *fontName = [[nsfont fontName] UTF8String];
636 int len = strlen (fontName);
638 #ifdef NS_IMPL_GNUSTEP
639 font_info->nsfont = sfont;
641 font_info->nsfont = nsfont;
643 [font_info->nsfont retain];
645 /* set up ns_font (defined in nsgui.h) */
646 font_info->name = (char *)xmalloc (strlen (fontName)+1);
647 bcopy (fontName, font_info->name, strlen (fontName)+1);
648 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
650 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
652 /* Metrics etc.; some fonts return an unusually large max advance, so we
653 only use it for fonts that have wide characters. */
654 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
655 [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
657 brect = [sfont boundingRectForFont];
658 full_height = brect.size.height;
659 min_height = [sfont ascender] - [sfont descender];
660 hd = full_height - min_height;
662 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
671 hshrink = 1 + expand / 2.0;
675 shrink = hshrink = 1.0;
678 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
679 font_info->underwidth = [sfont underlineThickness];
680 font_info->size = font->pixel_size;
681 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
684 font_info->max_bounds.ascent =
685 lrint (hshrink * [sfont ascender] + expand * hd/2);
686 font_info->max_bounds.descent =
687 -lrint (hshrink* [sfont descender] - expand*hd/2);
689 font_info->max_bounds.ascent + font_info->max_bounds.descent;
690 font_info->max_bounds.width = lrint (font_info->width);
691 font_info->max_bounds.lbearing = lrint (brect.origin.x);
692 font_info->max_bounds.rbearing =
693 lrint (brect.size.width - font_info->width);
694 /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
697 /* set up synthItal and the CG font */
698 font_info->synthItal = synthItal;
700 ATSFontRef atsFont = ATSFontFindFromPostScriptName
701 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
703 if (atsFont == kATSFontRefUnspecified)
705 /* see if we can get it by dropping italic (then synthesizing) */
706 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
707 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
708 fontName], kATSOptionFlagsDefault);
709 if (atsFont != kATSFontRefUnspecified)
710 font_info->synthItal = YES;
713 /* last resort fallback */
714 atsFont = ATSFontFindFromPostScriptName
715 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
718 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
722 /* set up metrics portion of font struct */
723 font->ascent = [sfont ascender];
724 font->descent = -[sfont descender];
725 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
726 font->space_width = lrint (nsfont_char_width (sfont, ' '));
727 font->average_width = lrint (font_info->width);
728 font->max_width = lrint (font_info->max_bounds.width);
729 font->height = lrint (font_info->height);
730 font->underline_position = lrint (font_info->underpos);
731 font->underline_thickness = lrint (font_info->underwidth);
733 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
734 font->props[FONT_FULLNAME_INDEX] =
735 make_unibyte_string (font_info->name, strlen (font_info->name));
743 /* Close FONT on frame F. */
745 nsfont_close (FRAME_PTR f, struct font *font)
747 struct nsfont_info *font_info = (struct nsfont_info *)font;
750 /* FIXME: this occurs apparently due to same failure to detect same font
751 that causes need for cache in nsfont_open ()
752 (came after unicode-2 -> trunk) */
756 for (i =0; i<0x100; i++)
758 if (font_info->glyphs[i])
759 xfree (font_info->glyphs[i]);
760 if (font_info->metrics[i])
761 xfree (font_info->metrics[i]);
763 [font_info->nsfont release];
765 CGFontRelease (font_info->cgfont);
767 xfree (font_info->name);
772 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
773 return 1. If not, return 0. If a font must be opened to check
776 nsfont_has_char (Lisp_Object entity, int c)
782 /* Return a glyph code of FONT for character C (Unicode code point).
783 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
785 nsfont_encode_char (struct font *font, int c)
787 struct nsfont_info *font_info = (struct nsfont_info *)font;
788 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
792 return FONT_INVALID_CODE;
794 /* did we already cache this block? */
795 if (!font_info->glyphs[high])
796 ns_uni_to_glyphs (font_info, high);
798 g = font_info->glyphs[high][low];
799 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
800 return g == 0xFFFF ? FONT_INVALID_CODE : g;
804 /* Perform the size computation of glyphs of FONT and fill in members
805 of METRICS. The glyphs are specified by their glyph codes in
806 CODE (length NGLYPHS). */
808 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
809 struct font_metrics *metrics)
811 struct nsfont_info *font_info = (struct nsfont_info *)font;
812 struct font_metrics *pcm;
813 unsigned char high, low;
817 bzero (metrics, sizeof (struct font_metrics));
819 for (i =0; i<nglyphs; i++)
821 /* get metrics for this glyph, filling cache if need be */
822 /* TODO: get metrics for whole string from an NSLayoutManager
824 high = (code[i] & 0xFF00) >> 8;
825 low = code[i] & 0x00FF;
826 if (!font_info->metrics[high])
827 ns_glyph_metrics (font_info, high);
828 pcm = &(font_info->metrics[high][low]);
830 if (metrics->lbearing > totalWidth + pcm->lbearing)
831 metrics->lbearing = totalWidth + pcm->lbearing;
832 if (metrics->rbearing < totalWidth + pcm->rbearing)
833 metrics->rbearing = totalWidth + pcm->rbearing;
834 if (metrics->ascent < pcm->ascent)
835 metrics->ascent = pcm->ascent;
836 if (metrics->descent < pcm->descent)
837 metrics->descent = pcm->descent;
839 totalWidth += pcm->width;
842 metrics->width = totalWidth;
844 return totalWidth; /* not specified in doc, but xfont.c does it */
848 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
849 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
850 is nonzero, fill the background in advance. It is assured that
851 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
853 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
855 /* NOTE: focus and clip must be set
856 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
858 static char cbuf[1024];
860 #ifdef NS_IMPL_GNUSTEP
861 static float advances[1024];
862 float *adv = advances;
864 static CGSize advances[1024];
865 CGSize *adv = advances;
869 struct nsfont_info *font = ns_tmp_font;
870 NSColor *col, *bgCol;
871 unsigned short *t = s->char2b;
874 /* Select face based on input flags */
875 switch (ns_tmp_flags)
877 case NS_DUMPGLYPH_CURSOR:
880 case NS_DUMPGLYPH_MOUSEFACE:
881 face = FACE_FROM_ID (s->f,
882 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
884 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
891 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
892 r.origin.x += abs (s->face->box_line_width);
895 r.size.height = FONT_HEIGHT (font);
897 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
898 NS to render the string, it will come out differently from the individual
899 character widths added up because of layout processing. */
902 int cwidth, twidth = 0;
904 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
905 /* FIXME: composition: no vertical displacement is considered. */
906 t += s->cmp_from; /* advance into composition */
907 for (i = s->cmp_from; i < s->nchars; i++, t++)
909 hi = (*t & 0xFF00) >> 8;
913 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
917 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
918 ns_glyph_metrics (font, hi);
919 cwidth = font->metrics[hi][lo].width;
922 #ifdef NS_IMPL_GNUSTEP
924 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
926 (*adv++).width = cwidth;
929 len = adv - advances;
930 r.size.width = twidth;
934 /* fill background if requested */
938 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
939 int mbox_line_width = max (s->face->box_line_width, 0);
941 if (s->row->full_width_p)
943 if (br.origin.x <= fibw + 1 + mbox_line_width)
945 br.size.width += br.origin.x - mbox_line_width;
946 br.origin.x = mbox_line_width;
948 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
950 br.size.width += fibw;
952 if (s->face->box == FACE_NO_BOX)
954 /* expand unboxed top row over internal border */
955 if (br.origin.y <= fibw + 1 + mbox_line_width)
957 br.size.height += br.origin.y;
963 int correction = abs (s->face->box_line_width)+1;
964 br.origin.y += correction;
965 br.size.height -= 2*correction;
966 br.origin.x += correction;
967 br.size.width -= 2*correction;
970 if (!s->face->stipple)
971 [(NS_FACE_BACKGROUND (face) != 0
972 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
973 : FRAME_BACKGROUND_COLOR (s->f)) set];
976 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
977 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
983 /* set up for character rendering */
984 r.origin.y += font->voffset + (s->height - font->height)/2;
986 col = (NS_FACE_FOREGROUND (face) != 0
987 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
988 : FRAME_FOREGROUND_COLOR (s->f));
989 /* FIXME: find another way to pass this */
990 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
991 : (NS_FACE_BACKGROUND (face) != 0
992 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
993 : FRAME_BACKGROUND_COLOR (s->f)));
995 /* render under GNUstep using DPS */
996 #ifdef NS_IMPL_GNUSTEP
998 NSGraphicsContext *context = GSCurrentContext ();
1003 /* do erase if "foreground" mode */
1007 DPSmoveto (context, r.origin.x, r.origin.y);
1008 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1009 DPSxshow (context, cbuf, advances, len);
1010 DPSstroke (context);
1012 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1016 if (face->underline_p)
1018 if (face->underline_color != 0)
1019 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1022 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1023 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1024 if (face->underline_color != 0)
1030 /* draw with DPSxshow () */
1031 DPSmoveto (context, r.origin.x, r.origin.y);
1032 DPSxshow (context, cbuf, advances, len);
1033 DPSstroke (context);
1035 DPSgrestore (context);
1039 #else /* NS_IMPL_COCOA */
1041 CGContextRef gcontext =
1042 [[NSGraphicsContext currentContext] graphicsPort];
1043 static CGAffineTransform fliptf;
1044 static BOOL firstTime = YES;
1049 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1052 CGContextSaveGState (gcontext);
1054 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1056 CGContextSetFont (gcontext, font->cgfont);
1057 CGContextSetFontSize (gcontext, font->size);
1058 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1059 CGContextSetShouldAntialias (gcontext, 0);
1061 CGContextSetShouldAntialias (gcontext, 1);
1062 if (EQ (ns_use_qd_smoothing, Qt))
1063 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1065 CGContextSetTextMatrix (gcontext, fliptf);
1069 /* foreground drawing; erase first to avoid overstrike */
1071 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1072 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1073 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1074 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1077 if (face->underline_p)
1079 if (face->underline_color != 0)
1080 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1083 CGContextBeginPath (gcontext);
1084 CGContextMoveToPoint (gcontext,
1085 r.origin.x, r.origin.y + font->underpos);
1086 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1087 r.origin.y + font->underpos);
1088 CGContextStrokePath (gcontext);
1089 if (face->underline_color != 0)
1095 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1096 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1099 if (face->overstrike)
1101 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1102 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1106 CGContextRestoreGState (gcontext);
1109 #endif /* NS_IMPL_COCOA */
1114 /* Auto-creates a fontset built around the font in font_object,
1115 by creating an attributed string with characters from each
1116 script, then requesting the NS text system to fix attributes
1118 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1120 Lisp_Object script, famAndReg;
1121 struct nsfont_info *font_info =
1122 (struct nsfont_info *)XFONT_OBJECT (font_object);
1124 /* NS text system (and char buf) init */
1125 static NSTextStorage *store;
1126 static NSLayoutManager *layout;
1127 static NSRange range;
1128 static NSMutableDictionary *attribs;
1129 static Lisp_Object *scripts;
1130 static int nscripts;
1131 static int *scriptsNchars;
1132 static BOOL firstTime = YES;
1133 Lisp_Object regString = build_string ("iso10646-1");
1136 if (firstTime == YES)
1138 nscripts = XINT (Flength (Vscript_representative_chars));
1139 scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1140 unsigned char *buf = malloc (4*nscripts*sizeof (char));
1141 Lisp_Object scriptsChars = Vscript_representative_chars;
1142 unsigned char *tpos = buf;
1144 scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1146 for (i =0; i<nscripts; i++)
1148 Lisp_Object sChars = XCAR (scriptsChars);
1149 Lisp_Object chars = XCDR (sChars);
1150 unsigned int ch, c =0;
1151 scripts[i] = XCAR (sChars);
1153 while (CONSP (chars))
1155 ch = XUINT (XCAR (chars));
1156 chars = XCDR (chars);
1157 CHAR_STRING_ADVANCE (ch, tpos);
1160 scriptsNchars[i] = c;
1162 scriptsChars = XCDR (scriptsChars);
1166 store = [[NSTextStorage alloc] init];
1167 layout = [[NSLayoutManager alloc] init];
1168 [store addLayoutManager: layout];
1171 [store beginEditing];
1172 [[store mutableString] appendString:
1173 [NSString stringWithUTF8String: buf]];
1177 range = NSMakeRange (0, [store length]);
1179 attribs = [[NSMutableDictionary alloc] init];
1184 [store beginEditing];
1185 [store removeAttribute: NSFontAttributeName range: range];
1186 [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1187 [store addAttributes: attribs range: range];
1192 NSMutableDictionary *map =
1193 [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1194 NSEnumerator *fonts;
1195 NSFont *cfont = nil, *tfont;
1199 for (i =0; i<nscripts; i++)
1201 [map removeAllObjects];
1202 for (j =0; j<scriptsNchars[i]; j++)
1204 cfont = [store attribute: NSFontAttributeName atIndex: idx++
1205 effectiveRange: NULL];
1206 n = [map objectForKey: cfont];
1208 n = [NSNumber numberWithInt: 1];
1210 n = [NSNumber numberWithInt: [n intValue] + 1];
1211 [map setObject: n forKey: cfont];
1214 /* majority rules */
1216 fonts = [map keyEnumerator];
1217 while (tfont = [fonts nextObject])
1219 n = [map objectForKey: tfont];
1220 if ([n intValue] > max)
1229 char *family = strdup([[cfont familyName] UTF8String]);
1230 Lisp_Object famAndReg;
1232 nsfont_escape_name (family);
1233 famAndReg = Fcons (build_string (family), regString);
1236 fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1237 font_info->name, family,
1238 SDATA (SYMBOL_NAME (scripts[i])));
1240 /* TODO: Some of the "scripts" in script-representative-chars are
1241 actually only "sub-scripts" which are not fully defined. For
1242 these, calling set_fontset_font generates an abort. Try to
1243 guess which ones these are and avoid it. */
1244 if (strstr (SDATA (SYMBOL_NAME (scripts[i])), "mathematical-")
1245 != SDATA (SYMBOL_NAME (scripts[i])))
1246 Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1251 fprintf (stderr, "%s fontset: none found for script '%s'\n",
1252 font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1254 } /* for i = script */
1260 /* ==========================================================================
1262 Font glyph and metrics caching functions
1264 ========================================================================== */
1266 /* Find and cache corresponding glyph codes for unicode values in given
1267 hi-byte block of 256. */
1269 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1271 #ifdef NS_IMPL_COCOA
1272 static EmacsGlyphStorage *glyphStorage;
1273 static char firstTime = 1;
1275 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1276 unsigned int i, g, idx;
1277 unsigned short *glyphs;
1280 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1285 #ifdef NS_IMPL_COCOA
1289 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1293 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1294 if (!unichars || !(font_info->glyphs[block]))
1297 /* create a string containing all unicode characters in this block */
1298 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1299 if (idx < 0xD800 || idx > 0xDFFF)
1302 unichars[i] = 0xFEFF;
1303 unichars[0x100] = 0;
1306 #ifdef NS_IMPL_COCOA
1307 NSString *allChars = [[NSString alloc]
1308 initWithCharactersNoCopy: unichars
1311 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1312 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1313 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1314 unsigned int gInd =0, cInd =0;
1316 [glyphStorage setString: allChars font: font_info->nsfont];
1317 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1318 desiredNumberOfCharacters: glyphStorage->maxChar
1319 glyphIndex: &gInd characterIndex: &cInd];
1321 glyphs = font_info->glyphs[block];
1322 for (i =0; i<0x100; i++, glyphs++)
1324 #ifdef NS_IMPL_GNUSTEP
1327 g = glyphStorage->cglyphs[i];
1328 /* TODO: is this a good check? maybe need to use coveredChars.. */
1330 g = 0xFFFF; /* hopefully unused... */
1335 #ifdef NS_IMPL_COCOA
1345 /* Determine and cache metrics for corresponding glyph codes in given
1346 hi-byte block of 256. */
1348 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1351 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1353 struct font_metrics *metrics;
1356 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1359 #ifdef NS_IMPL_GNUSTEP
1360 /* not implemented yet (as of startup 0.18), so punt */
1362 numGlyphs = 0x10000;
1366 sfont = [font_info->nsfont screenFont];
1368 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1369 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1370 if (!(font_info->metrics[block]))
1373 metrics = font_info->metrics[block];
1374 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1377 NSRect r = [sfont boundingRectForGlyph: g];
1379 #ifdef NS_IMPL_GNUSTEP
1382 NSString *s = [NSString stringWithFormat: @"%c", g];
1383 w = [sfont widthOfString: s];
1386 w = [sfont advancementForGlyph: g].width;
1389 metrics->width = lrint (w);
1392 rb = r.size.width - w;
1394 metrics->lbearing = round (lb);
1395 if (font_info->ital)
1396 rb += 0.22 * font_info->height;
1397 metrics->rbearing = lrint (w + rb);
1399 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1400 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1401 metrics->ascent = r.size.height - metrics->descent;
1402 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1408 #ifdef NS_IMPL_COCOA
1409 /* helper for font glyph setup */
1410 @implementation EmacsGlyphStorage
1414 return [self initWithCapacity: 1024];
1417 - initWithCapacity: (unsigned long) c
1419 self = [super init];
1422 dict = [NSMutableDictionary new];
1423 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1436 - (void) setString: (NSString *)str font: (NSFont *)font
1438 [dict setObject: font forKey: NSFontAttributeName];
1439 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1440 maxChar = [str length];
1444 /* NSGlyphStorage protocol */
1445 - (unsigned int)layoutOptions
1450 - (NSAttributedString *)attributedString
1455 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1456 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1457 characterIndex: (unsigned int)charIndex
1459 len = glyphIndex+length;
1460 for (i =glyphIndex; i<len; i++)
1461 cglyphs[i] = glyphs[i-glyphIndex];
1466 - (void)setIntAttribute: (int)attributeTag value: (int)val
1467 forGlyphAtIndex: (unsigned)glyphIndex
1473 #endif /* NS_IMPL_COCOA */
1478 dump_glyphstring (struct glyph_string *s)
1482 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1483 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1484 s->row->overlapping_p, s->background_filled_p);
1485 for (i =0; i<s->nchars; i++)
1486 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1487 fprintf (stderr, "\n");
1495 nsfont_driver.type = Qns;
1496 register_font_driver (&nsfont_driver, NULL);
1497 DEFSYM (Qapple, "apple");
1498 DEFSYM (Qroman, "roman");
1499 DEFSYM (Qmedium, "medium");
1502 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae