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
125 : (n < STYLE_REF) ? NSUnboldFontMask : 0;
127 n = FONT_SLANT_NUMERIC (font_spec);
129 traits |= (n > STYLE_REF) ? NSItalicFontMask
130 : (n < STYLE_REF) ? NSUnitalicFontMask : 0;
132 n = FONT_WIDTH_NUMERIC (font_spec);
134 traits |= (n > STYLE_REF + 10) ? NSExpandedFontMask
135 : (n < STYLE_REF - 10) ? NSExpandedFontMask : 0;
137 /*fprintf (stderr, " returning traits = %u\n", traits); */
142 /* Converts NSArray of PS name, non-family part, weight, and traits to a
143 font backend font-entity. */
145 nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
147 Lisp_Object font_entity = font_make_entity ();
148 unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
149 /* NSString *psName = [famMember objectAtIndex: 0]; */
150 NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
151 char *escapedFamily = strdup ([family UTF8String]);
153 nsfont_escape_name (escapedFamily);
154 [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
155 range: NSMakeRange (0, [suffix length])];
157 ASET (font_entity, FONT_TYPE_INDEX, Qns);
158 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
159 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
160 ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
161 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
163 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
164 traits & NSBoldFontMask ? Qbold : Qmedium);
165 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
166 traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
167 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
168 traits & NSCondensedFontMask ? Qcondensed :
169 traits & NSExpandedFontMask ? Qexpanded : Qnormal);
171 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
172 ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
173 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
177 fprintf (stderr, "created font_entity:\n ");
178 debug_print (font_entity);
182 free (escapedFamily);
187 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
189 nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
192 for (i = 0; i < sizeof (unsigned int) * 8; i++)
194 d += (traits1 & 0x1) ^ (traits2 & 0x1);
202 /* Default font entity based on Monaco. */
204 nsfont_fallback_entity ()
206 NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
207 NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
208 [NSNumber numberWithUnsignedInt: 5],
209 [NSNumber numberWithUnsignedInt: 0], nil];
210 return nsfont_fmember_to_entity (family, famMemberSpec);
214 /* ==========================================================================
216 Font driver implementation
218 ========================================================================== */
220 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
221 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
222 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
223 static Lisp_Object nsfont_list_family (Lisp_Object frame);
224 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
226 static void nsfont_close (FRAME_PTR f, struct font *font);
227 static int nsfont_has_char (Lisp_Object entity, int c);
228 static unsigned int nsfont_encode_char (struct font *font, int c);
229 static int nsfont_text_extents (struct font *font, unsigned int *code,
230 int nglyphs, struct font_metrics *metrics);
231 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
232 int with_background);
234 struct font_driver nsfont_driver =
237 1, /* case sensitive */
242 NULL, /*free_entity */
245 NULL, /* prepare_face */
246 NULL, /* done_face */
251 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
252 anchor_point, otf_capability, otf_driver,
253 start_for_frame, end_for_frame, shape */
257 /* Return a cache of font-entities on FRAME. The cache must be a
258 cons whose cdr part is the actual cache area. */
260 nsfont_get_cache (FRAME_PTR frame)
262 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
263 return (dpyinfo->name_list_element);
267 /* List fonts exactly matching with FONT_SPEC on FRAME. The value
268 is a **list** of font-entities. This is the sole API that
269 allocates font-entities. */
271 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
273 Lisp_Object list = Qnil;
277 NSEnumerator *famEnum;
278 NSFontManager *fontMgr;
279 unsigned int traits = nsfont_spec_to_traits (font_spec);
283 fprintf (stderr, "nsfont: list for fontspec:\n ");
284 debug_print (font_spec);
287 /* if has non-unicode registry, give up */
288 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
289 if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
292 fontMgr = [NSFontManager sharedFontManager];
294 family = nsfont_get_family (font_spec);
297 families = [NSArray arrayWithObject: family];
299 families = [fontMgr availableFontFamilies];
301 for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
304 NSArray *fmember, *firstMember = nil;
305 unsigned int mtraits;
306 BOOL foundItal = NO || (traits & NSUnitalicFontMask);
307 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
309 /* LastResort is special: not a family but a font name only */
310 if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
312 famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
313 @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
314 [NSNumber numberWithUnsignedInt: 0], nil]];
318 /* fmember = [postscriptName style weight traits] */
319 fm = [famMembers objectEnumerator];
320 while (fmember = [fm nextObject])
322 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
323 if ((mtraits & traits) == traits)
325 list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
326 if (mtraits & NSItalicFontMask)
328 if (firstMember == nil)
329 firstMember = fmember;
332 if (foundItal == NO && firstMember != nil)
334 /* no italic member found; add a synthesized one */
335 NSMutableArray *smember = [firstMember mutableCopy];
336 [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
337 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
338 mtraits |= NSItalicFontMask;
339 [smember replaceObjectAtIndex: 3
340 withObject: [NSNumber numberWithUnsignedInt: mtraits]];
341 /*NSLog (@"-- adding synthItal member: %@", smember); */
342 list = Fcons (nsfont_fmember_to_entity (family, smember), list);
348 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
354 /* Return a font entity most closely maching with FONT_SPEC on
355 FRAME. The closeness is determined by the font backend, thus
356 `face-font-selection-order' is ignored here. */
358 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
360 long traits = nsfont_spec_to_traits (font_spec);
361 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
367 fprintf (stderr, "nsfont: match for fontspec:\n ");
368 debug_print (font_spec);
371 /* if has non-unicode registry, just return fallback */
373 tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
375 fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
377 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
378 if (!NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
379 return nsfont_fallback_entity ();
381 family = nsfont_get_family (font_spec);
385 /* try to find close font in family */
386 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
387 NSEnumerator *fm = [famMembers objectEnumerator];
389 int minDist = sizeof (unsigned int) * 8 + 1;
390 int bestMatchIdx = -1;
393 for (i =0; fmember = [fm nextObject]; i++)
395 unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
396 int dist = nsfont_trait_distance ((mtraits & traits), traits);
403 if (bestMatchIdx != -1)
404 return nsfont_fmember_to_entity
405 (family, [famMembers objectAtIndex: bestMatchIdx]);
408 /* no family that had members was given; find any font matching traits */
410 NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
411 if (fontNames && [fontNames count] > 0)
413 NSString *fontName = [fontNames objectAtIndex: 0];
414 /* XXX: is there a more efficient way to get family name? */
415 NSFont *font = [NSFont fontWithName: fontName size: 0];
418 /* now need to get suffix part of name.. */
419 NSString *family = [font familyName];
420 NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
423 while (fmember = [fm nextObject])
425 unsigned int mtraits =
426 [[fmember objectAtIndex: 3] unsignedIntValue];
427 if (mtraits & traits == traits)
428 return nsfont_fmember_to_entity (family, fmember);
434 /* if we get here, return the fallback */
436 fprintf (stderr, " *** returning fallback\n");
438 return nsfont_fallback_entity ();
442 /* List available families. The value is a list of family names
445 nsfont_list_family (Lisp_Object frame)
447 Lisp_Object list = Qnil;
448 NSEnumerator *families =
449 [[[NSFontManager sharedFontManager] availableFontFamilies]
452 while (family = [families nextObject])
453 list = Fcons (intern ([family UTF8String]), list);
454 /* FIXME: escape the name? */
457 fprintf (stderr, "nsfont: list families returning %d entries\n",
458 XINT (Flength (list)));
464 /* utility: get width of a char c in screen font sfont */
466 nsfont_char_width (NSFont *sfont, int c)
469 NSString *cstr = [NSString stringWithFormat: @"%c", c];
471 NSGlyph glyph = [sfont glyphWithName: cstr];
474 float w = [sfont advancementForGlyph: glyph].width;
479 w = [sfont widthOfString: cstr];
484 /* Open a font specified by FONT_ENTITY on frame F. If the font is
485 scalable, open it with PIXEL_SIZE. */
487 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
490 struct nsfont_info *font_info;
492 unsigned int traits = nsfont_spec_to_traits (font_entity);
493 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
495 NSFont *nsfont, *sfont;
498 Lisp_Object font_object;
501 static NSMutableDictionary *fontCache = nil;
504 /* 2008/03/08: The same font may end up being requested for different
505 entities, due to small differences in numeric values or other issues,
506 or for different copies of the same entity. Therefore we cache to
507 avoid creating multiple struct font objects (with metrics cache, etc.)
508 for the same NSFont object.
509 2008/06/01: This is still an issue after font backend refactoring. */
510 if (fontCache == nil)
511 fontCache = [[NSMutableDictionary alloc] init];
515 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
516 debug_print (font_entity);
521 /* try to get it out of frame params */
522 Lisp_Object tem = get_frame_param (f, Qfontsize);
523 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
526 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
527 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
529 family = nsfont_get_family (font_entity);
532 fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\titalic = %d\n",
533 [family UTF8String], traits, traits & NSBoldFontMask,
534 traits & NSItalicFontMask);
537 /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
538 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
539 nsfont = [fontMgr fontWithFamily: family
540 traits: traits weight: fixLeopardBug
542 /* if didn't find, try synthetic italic */
543 if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
545 nsfont = [fontMgr fontWithFamily: family
546 traits: traits & ~NSItalicFontMask
547 weight: fixLeopardBug size: pixel_size];
550 /* LastResort not really a family */
551 if (nsfont == nil && [@"LastResort" isEqualToString: family])
553 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
559 message_with_string ("*** Warning: font in family '%s' not found",
560 build_string ([family UTF8String]), 1);
561 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
564 fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
570 NSLog (@"%@\n", nsfont);
572 /* Check the cache */
573 cached = [fontCache objectForKey: nsfont];
574 if (cached != nil && !synthItal)
577 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
578 return (Lisp_Object)[cached unsignedLongValue];
582 font_object = font_make_object (VECSIZE (struct nsfont_info),
583 font_entity, pixel_size);
586 setObject: [NSNumber numberWithUnsignedLong:
587 (unsigned long)font_object]
591 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
592 font = (struct font *)font_info;
594 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
596 font_info->glyphs = (unsigned short **)
597 xmalloc (0x100 * sizeof (unsigned short *));
598 font_info->metrics = (struct font_metrics **)
599 xmalloc (0x100 * sizeof (struct font_metrics *));
600 if (!font_info->glyphs || !font_info->metrics)
602 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
603 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
608 sfont = [nsfont screenFont];
612 /* non-metric backend font struct fields */
613 font = (struct font *) font_info;
614 font->pixel_size = [sfont pointSize];
615 font->driver = &nsfont_driver;
616 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
617 font->encoding_charset = -1;
618 font->repertory_charset = -1;
619 font->default_ascent = 0;
620 font->vertical_centering = 0;
621 font->baseline_offset = 0;
622 font->relative_compose = 0;
623 font->font_encoder = NULL;
625 /* TODO: does anything care about this? */
626 font->props[FONT_FORMAT_INDEX] = Qns;
627 font->props[FONT_FILE_INDEX] = Qnil;
630 double expand, shrink, hshrink;
631 float full_height, min_height, hd;
632 const char *fontName = [[nsfont fontName] UTF8String];
633 int len = strlen (fontName);
635 #ifdef NS_IMPL_GNUSTEP
636 font_info->nsfont = sfont;
638 font_info->nsfont = nsfont;
640 [font_info->nsfont retain];
642 /* set up ns_font (defined in nsgui.h) */
643 font_info->name = (char *)xmalloc (strlen (fontName)+1);
644 bcopy (fontName, font_info->name, strlen (fontName)+1);
645 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
647 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
649 /* Metrics etc.; some fonts return an unusually large max advance, so we
650 only use it for fonts that have wide characters. */
651 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
652 [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
654 brect = [sfont boundingRectForFont];
655 full_height = brect.size.height;
656 min_height = [sfont ascender] - [sfont descender];
657 hd = full_height - min_height;
659 if (!NUMBERP (ns_expand_space))
660 error ("No expand space defined");
662 /* ns_expand_space = 0.0 is use standard height; less shrink, more expand */
663 expand = XFLOATINT (ns_expand_space) + 0.5;
668 hshrink = 1 + expand / 2.0;
672 shrink = hshrink = 1.0;
674 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
675 font_info->underwidth = [sfont underlineThickness];
676 font_info->size = font->pixel_size;
677 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
680 font_info->max_bounds.ascent =
681 lrint (hshrink * [sfont ascender] + expand * hd/2);
682 font_info->max_bounds.descent =
683 -lrint (hshrink* [sfont descender] - expand*hd/2);
685 font_info->max_bounds.ascent + font_info->max_bounds.descent;
686 font_info->max_bounds.width = lrint (font_info->width);
687 font_info->max_bounds.lbearing = lrint (brect.origin.x);
688 font_info->max_bounds.rbearing =
689 lrint (brect.size.width - font_info->width);
690 /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
693 /* set up synthItal and the CG font */
694 font_info->synthItal = synthItal;
696 ATSFontRef atsFont = ATSFontFindFromPostScriptName
697 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
699 if (atsFont == kATSFontRefUnspecified)
701 /* see if we can get it by dropping italic (then synthesizing) */
702 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
703 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
704 fontName], kATSOptionFlagsDefault);
705 if (atsFont != kATSFontRefUnspecified)
706 font_info->synthItal = YES;
709 /* last resort fallback */
710 atsFont = ATSFontFindFromPostScriptName
711 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
714 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
718 /* set up metrics portion of font struct */
719 font->ascent = [sfont ascender];
720 font->descent = -[sfont descender];
721 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
722 font->space_width = lrint (nsfont_char_width (sfont, ' '));
723 font->average_width = lrint (font_info->width);
724 font->max_width = lrint (font_info->max_bounds.width);
725 font->height = lrint (font_info->height);
726 font->underline_position = lrint (font_info->underpos);
727 font->underline_thickness = lrint (font_info->underwidth);
729 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
730 font->props[FONT_FULLNAME_INDEX] =
731 make_unibyte_string (font_info->name, strlen (font_info->name));
739 /* Close FONT on frame F. */
741 nsfont_close (FRAME_PTR f, struct font *font)
743 struct nsfont_info *font_info = (struct nsfont_info *)font;
746 /* FIXME: this occurs apparently due to same failure to detect same font
747 that causes need for cache in nsfont_open ()
748 (came after unicode-2 -> trunk) */
752 for (i =0; i<0x100; i++)
754 if (font_info->glyphs[i])
755 xfree (font_info->glyphs[i]);
756 if (font_info->metrics[i])
757 xfree (font_info->metrics[i]);
759 [font_info->nsfont release];
761 CGFontRelease (font_info->cgfont);
763 xfree (font_info->name);
768 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
769 return 1. If not, return 0. If a font must be opened to check
772 nsfont_has_char (Lisp_Object entity, int c)
778 /* Return a glyph code of FONT for character C (Unicode code point).
779 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
781 nsfont_encode_char (struct font *font, int c)
783 struct nsfont_info *font_info = (struct nsfont_info *)font;
784 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
788 return FONT_INVALID_CODE;
790 /* did we already cache this block? */
791 if (!font_info->glyphs[high])
792 ns_uni_to_glyphs (font_info, high);
794 g = font_info->glyphs[high][low];
795 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
796 return g == 0xFFFF ? FONT_INVALID_CODE : g;
800 /* Perform the size computation of glyphs of FONT and fill in members
801 of METRICS. The glyphs are specified by their glyph codes in
802 CODE (length NGLYPHS). */
804 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
805 struct font_metrics *metrics)
807 struct nsfont_info *font_info = (struct nsfont_info *)font;
808 struct font_metrics *pcm;
809 unsigned char high, low;
813 bzero (metrics, sizeof (struct font_metrics));
815 for (i =0; i<nglyphs; i++)
817 /* get metrics for this glyph, filling cache if need be */
818 /* TODO: get metrics for whole string from an NSLayoutManager
820 high = (code[i] & 0xFF00) >> 8;
821 low = code[i] & 0x00FF;
822 if (!font_info->metrics[high])
823 ns_glyph_metrics (font_info, high);
824 pcm = &(font_info->metrics[high][low]);
826 if (metrics->lbearing > totalWidth + pcm->lbearing)
827 metrics->lbearing = totalWidth + pcm->lbearing;
828 if (metrics->rbearing < totalWidth + pcm->rbearing)
829 metrics->rbearing = totalWidth + pcm->rbearing;
830 if (metrics->ascent < pcm->ascent)
831 metrics->ascent = pcm->ascent;
832 if (metrics->descent < pcm->descent)
833 metrics->descent = pcm->descent;
835 totalWidth += pcm->width;
838 metrics->width = totalWidth;
840 return totalWidth; /* not specified in doc, but xfont.c does it */
844 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
845 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
846 is nonzero, fill the background in advance. It is assured that
847 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
849 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
851 /* NOTE: focus and clip must be set
852 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
854 static char cbuf[1024];
856 #ifdef NS_IMPL_GNUSTEP
857 static float advances[1024];
858 float *adv = advances;
860 static CGSize advances[1024];
861 CGSize *adv = advances;
865 struct nsfont_info *font = ns_tmp_font;
866 NSColor *col, *bgCol;
867 unsigned short *t = s->char2b;
870 /* Select face based on input flags */
871 switch (ns_tmp_flags)
873 case NS_DUMPGLYPH_CURSOR:
876 case NS_DUMPGLYPH_MOUSEFACE:
877 face = FACE_FROM_ID (s->f,
878 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
880 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
887 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
888 r.origin.x += abs (s->face->box_line_width);
891 r.size.height = FONT_HEIGHT (font);
893 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
894 NS to render the string, it will come out differently from the individual
895 character widths added up because of layout processing. */
898 int cwidth, twidth = 0;
900 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
901 /* FIXME: composition: no vertical displacement is considered. */
902 t += s->cmp_from; /* advance into composition */
903 for (i = s->cmp_from; i < s->nchars; i++, t++)
905 hi = (*t & 0xFF00) >> 8;
909 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
913 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
914 ns_glyph_metrics (font, hi);
915 cwidth = font->metrics[hi][lo].width;
918 #ifdef NS_IMPL_GNUSTEP
920 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
922 (*adv++).width = cwidth;
925 len = adv - advances;
926 r.size.width = twidth;
930 /* fill background if requested */
934 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
935 int mbox_line_width = max (s->face->box_line_width, 0);
937 if (s->row->full_width_p)
939 if (br.origin.x <= fibw + 1 + mbox_line_width)
941 br.size.width += br.origin.x - mbox_line_width;
942 br.origin.x = mbox_line_width;
944 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
946 br.size.width += fibw;
948 if (s->face->box == FACE_NO_BOX)
950 /* expand unboxed top row over internal border */
951 if (br.origin.y <= fibw + 1 + mbox_line_width)
953 br.size.height += br.origin.y;
959 int correction = abs (s->face->box_line_width)+1;
960 br.origin.y += correction;
961 br.size.height -= 2*correction;
962 br.origin.x += correction;
963 br.size.width -= 2*correction;
966 if (!s->face->stipple)
967 [(NS_FACE_BACKGROUND (face) != 0
968 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
969 : FRAME_BACKGROUND_COLOR (s->f)) set];
972 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
973 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
979 /* set up for character rendering */
980 r.origin.y += font->voffset + (s->height - font->height)/2;
982 col = (NS_FACE_FOREGROUND (face) != 0
983 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
984 : FRAME_FOREGROUND_COLOR (s->f));
985 /* FIXME: find another way to pass this */
986 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
987 : (NS_FACE_BACKGROUND (face) != 0
988 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
989 : FRAME_BACKGROUND_COLOR (s->f)));
991 /* render under GNUstep using DPS */
992 #ifdef NS_IMPL_GNUSTEP
994 NSGraphicsContext *context = GSCurrentContext ();
999 /* do erase if "foreground" mode */
1003 DPSmoveto (context, r.origin.x, r.origin.y);
1004 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1005 DPSxshow (context, cbuf, advances, len);
1006 DPSstroke (context);
1008 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1012 if (face->underline_p)
1014 if (face->underline_color != 0)
1015 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1018 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1019 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1020 if (face->underline_color != 0)
1026 /* draw with DPSxshow () */
1027 DPSmoveto (context, r.origin.x, r.origin.y);
1028 DPSxshow (context, cbuf, advances, len);
1029 DPSstroke (context);
1031 DPSgrestore (context);
1035 #else /* NS_IMPL_COCOA */
1037 CGContextRef gcontext =
1038 [[NSGraphicsContext currentContext] graphicsPort];
1039 static CGAffineTransform fliptf;
1040 static BOOL firstTime = YES;
1045 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1048 CGContextSaveGState (gcontext);
1050 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1052 CGContextSetFont (gcontext, font->cgfont);
1053 CGContextSetFontSize (gcontext, font->size);
1054 if (ns_antialias_text == NO || font->size <= ns_antialias_threshold)
1055 CGContextSetShouldAntialias (gcontext, 0);
1057 CGContextSetShouldAntialias (gcontext, 1);
1058 if (EQ (ns_use_qd_smoothing, Qt))
1059 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1061 CGContextSetTextMatrix (gcontext, fliptf);
1065 /* foreground drawing; erase first to avoid overstrike */
1067 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1068 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1069 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1070 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1073 if (face->underline_p)
1075 if (face->underline_color != 0)
1076 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1079 CGContextBeginPath (gcontext);
1080 CGContextMoveToPoint (gcontext,
1081 r.origin.x, r.origin.y + font->underpos);
1082 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1083 r.origin.y + font->underpos);
1084 CGContextStrokePath (gcontext);
1085 if (face->underline_color != 0)
1091 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1092 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1095 if (face->overstrike)
1097 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1098 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1102 CGContextRestoreGState (gcontext);
1105 #endif /* NS_IMPL_COCOA */
1110 /* Auto-creates a fontset built around the font in font_object,
1111 by creating an attributed string with characters from each
1112 script, then requesting the NS text system to fix attributes
1114 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1116 Lisp_Object script, famAndReg;
1117 struct nsfont_info *font_info =
1118 (struct nsfont_info *)XFONT_OBJECT (font_object);
1120 /* NS text system (and char buf) init */
1121 static NSTextStorage *store;
1122 static NSLayoutManager *layout;
1123 static NSRange range;
1124 static NSMutableDictionary *attribs;
1125 static Lisp_Object *scripts;
1126 static int nscripts;
1127 static int *scriptsNchars;
1128 static BOOL firstTime = YES;
1129 Lisp_Object regString = build_string ("iso10646-1");
1132 if (firstTime == YES)
1134 nscripts = XINT (Flength (Vscript_representative_chars));
1135 scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1136 unsigned char *buf = malloc (4*nscripts*sizeof (char));
1137 Lisp_Object scriptsChars = Vscript_representative_chars;
1138 unsigned char *tpos = buf;
1140 scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1142 for (i =0; i<nscripts; i++)
1144 Lisp_Object sChars = XCAR (scriptsChars);
1145 Lisp_Object chars = XCDR (sChars);
1146 unsigned int ch, c =0;
1147 scripts[i] = XCAR (sChars);
1149 while (CONSP (chars))
1151 ch = XUINT (XCAR (chars));
1152 chars = XCDR (chars);
1153 CHAR_STRING_ADVANCE (ch, tpos);
1156 scriptsNchars[i] = c;
1158 scriptsChars = XCDR (scriptsChars);
1162 store = [[NSTextStorage alloc] init];
1163 layout = [[NSLayoutManager alloc] init];
1164 [store addLayoutManager: layout];
1167 [store beginEditing];
1168 [[store mutableString] appendString:
1169 [NSString stringWithUTF8String: buf]];
1173 range = NSMakeRange (0, [store length]);
1175 attribs = [[NSMutableDictionary alloc] init];
1180 [store beginEditing];
1181 [store removeAttribute: NSFontAttributeName range: range];
1182 [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1183 [store addAttributes: attribs range: range];
1188 NSMutableDictionary *map =
1189 [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1190 NSEnumerator *fonts;
1191 NSFont *cfont = nil, *tfont;
1195 for (i =0; i<nscripts; i++)
1197 [map removeAllObjects];
1198 for (j =0; j<scriptsNchars[i]; j++)
1200 cfont = [store attribute: NSFontAttributeName atIndex: idx++
1201 effectiveRange: NULL];
1202 n = [map objectForKey: cfont];
1204 n = [NSNumber numberWithInt: 1];
1206 n = [NSNumber numberWithInt: [n intValue] + 1];
1207 [map setObject: n forKey: cfont];
1210 /* majority rules */
1212 fonts = [map keyEnumerator];
1213 while (tfont = [fonts nextObject])
1215 n = [map objectForKey: tfont];
1216 if ([n intValue] > max)
1225 char *family = strdup([[cfont familyName] UTF8String]);
1226 Lisp_Object famAndReg;
1228 nsfont_escape_name (family);
1229 famAndReg = Fcons (build_string (family), regString);
1232 fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1233 font_info->name, family,
1234 SDATA (SYMBOL_NAME (scripts[i])));
1236 Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1241 fprintf (stderr, "%s fontset: none found for script '%s'\n",
1242 font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1244 } /* for i = script */
1250 /* ==========================================================================
1252 Font glyph and metrics caching functions
1254 ========================================================================== */
1256 /* Find and cache corresponding glyph codes for unicode values in given
1257 hi-byte block of 256. */
1259 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1261 #ifdef NS_IMPL_COCOA
1262 static EmacsGlyphStorage *glyphStorage;
1263 static char firstTime = 1;
1265 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1266 unsigned int i, g, idx;
1267 unsigned short *glyphs;
1270 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1275 #ifdef NS_IMPL_COCOA
1279 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1283 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1284 if (!unichars || !(font_info->glyphs[block]))
1287 /* create a string containing all unicode characters in this block */
1288 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1289 if (idx < 0xD800 || idx > 0xDFFF)
1292 unichars[i] = 0xFEFF;
1293 unichars[0x100] = 0;
1296 #ifdef NS_IMPL_COCOA
1297 NSString *allChars = [[NSString alloc]
1298 initWithCharactersNoCopy: unichars
1301 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1302 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1303 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1304 unsigned int gInd =0, cInd =0;
1306 [glyphStorage setString: allChars font: font_info->nsfont];
1307 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1308 desiredNumberOfCharacters: glyphStorage->maxChar
1309 glyphIndex: &gInd characterIndex: &cInd];
1311 glyphs = font_info->glyphs[block];
1312 for (i =0; i<0x100; i++, glyphs++)
1314 #ifdef NS_IMPL_GNUSTEP
1317 g = glyphStorage->cglyphs[i];
1318 /* TODO: is this a good check? maybe need to use coveredChars.. */
1320 g = 0xFFFF; /* hopefully unused... */
1325 #ifdef NS_IMPL_COCOA
1335 /* Determine and cache metrics for corresponding glyph codes in given
1336 hi-byte block of 256. */
1338 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1341 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1343 struct font_metrics *metrics;
1346 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1349 #ifdef NS_IMPL_GNUSTEP
1350 /* not implemented yet (as of startup 0.18), so punt */
1352 numGlyphs = 0x10000;
1356 sfont = [font_info->nsfont screenFont];
1358 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1359 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1360 if (!(font_info->metrics[block]))
1363 metrics = font_info->metrics[block];
1364 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1367 NSRect r = [sfont boundingRectForGlyph: g];
1369 #ifdef NS_IMPL_GNUSTEP
1372 NSString *s = [NSString stringWithFormat: @"%c", g];
1373 w = [sfont widthOfString: s];
1376 w = [sfont advancementForGlyph: g].width;
1379 metrics->width = lrint (w);
1382 rb = r.size.width - w;
1384 metrics->lbearing = round (lb);
1385 if (font_info->ital)
1386 rb += 0.22 * font_info->height;
1387 metrics->rbearing = lrint (w + rb);
1389 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1390 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1391 metrics->ascent = r.size.height - metrics->descent;
1392 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1398 #ifdef NS_IMPL_COCOA
1399 /* helper for font glyph setup */
1400 @implementation EmacsGlyphStorage
1404 return [self initWithCapacity: 1024];
1407 - initWithCapacity: (unsigned long) c
1409 self = [super init];
1412 dict = [NSMutableDictionary new];
1413 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1426 - (void) setString: (NSString *)str font: (NSFont *)font
1428 [dict setObject: font forKey: NSFontAttributeName];
1429 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1430 maxChar = [str length];
1434 /* NSGlyphStorage protocol */
1435 - (unsigned int)layoutOptions
1440 - (NSAttributedString *)attributedString
1445 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1446 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1447 characterIndex: (unsigned int)charIndex
1449 len = glyphIndex+length;
1450 for (i =glyphIndex; i<len; i++)
1451 cglyphs[i] = glyphs[i-glyphIndex];
1456 - (void)setIntAttribute: (int)attributeTag value: (int)val
1457 forGlyphAtIndex: (unsigned)glyphIndex
1463 #endif /* NS_IMPL_COCOA */
1468 dump_glyphstring (struct glyph_string *s)
1472 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1473 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1474 s->row->overlapping_p, s->background_filled_p);
1475 for (i =0; i<s->nchars; i++)
1476 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1477 fprintf (stderr, "\n");
1485 nsfont_driver.type = Qns;
1486 register_font_driver (&nsfont_driver, NULL);
1487 DEFSYM (Qapple, "apple");
1488 DEFSYM (Qroman, "roman");
1489 DEFSYM (Qmedium, "medium");
1492 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae