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 ns_expand_space;
46 extern Lisp_Object Qappend;
47 extern int ns_antialias_text, ns_use_qd_smoothing;
48 extern float ns_antialias_threshold;
49 extern int ns_tmp_flags;
50 extern struct nsfont_info *ns_tmp_font;
52 /* font glyph and metrics caching functions, implemented at end */
53 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
55 static void ns_glyph_metrics (struct nsfont_info *font_info,
59 /* ==========================================================================
63 ========================================================================== */
66 /* Replace spaces w/another character so emacs core font parsing routines
69 nsfont_escape_name (char *name)
71 int i =0, len =strlen (name);
78 /* Reconstruct spaces in a font family name passed through emacs. */
80 nsfont_unescape_name (char *name)
82 int i =0, len =strlen (name);
89 /* Extract family name from a font spec. */
91 nsfont_get_family (Lisp_Object font_spec)
93 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
98 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
100 nsfont_unescape_name (tmp);
101 /* TODO: this seems to be needed only for font names that are
102 hard-coded into emacs, like 'helvetica' for splash screen */
104 tmp[0] = toupper (tmp[0]);
105 family = [NSString stringWithUTF8String: tmp];
112 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
113 /* TODO (20080601): The font backend's strategy for handling font
114 styles continues to evolve. When/if this stabilizes, we
115 can change the code here to be more sophisticated and accurate.
116 For now, we rely on "normal/plain" style being numeric 100. */
117 #define STYLE_REF 100
119 nsfont_spec_to_traits (Lisp_Object font_spec)
121 unsigned int traits = 0;
124 n = FONT_WEIGHT_NUMERIC (font_spec);
126 traits |= (n > STYLE_REF) ? NSBoldFontMask
127 : (n < STYLE_REF) ? NSUnboldFontMask : 0;
129 n = FONT_SLANT_NUMERIC (font_spec);
131 traits |= (n > STYLE_REF) ? NSItalicFontMask
132 : (n < STYLE_REF) ? NSUnitalicFontMask : 0;
134 n = FONT_WIDTH_NUMERIC (font_spec);
136 traits |= (n > STYLE_REF + 10) ? NSExpandedFontMask
137 : (n < STYLE_REF - 10) ? NSExpandedFontMask : 0;
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 **list** 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)));
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 (!NILP (tem) && !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;
503 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 after font backend refactoring. */
512 if (fontCache == nil)
513 fontCache = [[NSMutableDictionary alloc] init];
517 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
518 debug_print (font_entity);
523 /* try to get it out of frame params */
524 Lisp_Object tem = get_frame_param (f, Qfontsize);
525 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
528 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
529 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
531 family = nsfont_get_family (font_entity);
534 fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\titalic = %d\n",
535 [family UTF8String], traits, traits & NSBoldFontMask,
536 traits & NSItalicFontMask);
539 /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
540 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
541 nsfont = [fontMgr fontWithFamily: family
542 traits: traits weight: fixLeopardBug
544 /* if didn't find, try synthetic italic */
545 if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
547 nsfont = [fontMgr fontWithFamily: family
548 traits: traits & ~NSItalicFontMask
549 weight: fixLeopardBug size: pixel_size];
552 /* LastResort not really a family */
553 if (nsfont == nil && [@"LastResort" isEqualToString: family])
555 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
561 message_with_string ("*** Warning: font in family '%s' not found",
562 build_string ([family UTF8String]), 1);
563 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
566 fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
572 NSLog (@"%@\n", nsfont);
574 /* Check the cache */
575 cached = [fontCache objectForKey: nsfont];
576 if (cached != nil && !synthItal)
579 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
580 return (Lisp_Object)[cached unsignedLongValue];
584 font_object = font_make_object (VECSIZE (struct nsfont_info),
585 font_entity, pixel_size);
588 setObject: [NSNumber numberWithUnsignedLong:
589 (unsigned long)font_object]
593 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
594 font = (struct font *)font_info;
596 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
598 font_info->glyphs = (unsigned short **)
599 xmalloc (0x100 * sizeof (unsigned short *));
600 font_info->metrics = (struct font_metrics **)
601 xmalloc (0x100 * sizeof (struct font_metrics *));
602 if (!font_info->glyphs || !font_info->metrics)
604 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
605 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
610 sfont = [nsfont screenFont];
614 /* non-metric backend font struct fields */
615 font = (struct font *) font_info;
616 font->pixel_size = [sfont pointSize];
617 font->driver = &nsfont_driver;
618 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
619 font->encoding_charset = -1;
620 font->repertory_charset = -1;
621 font->default_ascent = 0;
622 font->vertical_centering = 0;
623 font->baseline_offset = 0;
624 font->relative_compose = 0;
625 font->font_encoder = NULL;
627 /* TODO: does anything care about this? */
628 font->props[FONT_FORMAT_INDEX] = Qns;
629 font->props[FONT_FILE_INDEX] = Qnil;
632 double expand, shrink, hshrink;
633 float full_height, min_height, hd;
634 const char *fontName = [[nsfont fontName] UTF8String];
635 int len = strlen (fontName);
637 #ifdef NS_IMPL_GNUSTEP
638 font_info->nsfont = sfont;
640 font_info->nsfont = nsfont;
642 [font_info->nsfont retain];
644 /* set up ns_font (defined in nsgui.h) */
645 font_info->name = (char *)xmalloc (strlen (fontName)+1);
646 bcopy (fontName, font_info->name, strlen (fontName)+1);
647 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
649 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
651 /* Metrics etc.; some fonts return an unusually large max advance, so we
652 only use it for fonts that have wide characters. */
653 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
654 [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
656 brect = [sfont boundingRectForFont];
657 full_height = brect.size.height;
658 min_height = [sfont ascender] - [sfont descender];
659 hd = full_height - min_height;
661 if (!NUMBERP (ns_expand_space))
662 error ("No expand space defined");
664 /* ns_expand_space = 0.0 is use standard height; less shrink, more expand */
665 expand = XFLOATINT (ns_expand_space) + 0.5;
670 hshrink = 1 + expand / 2.0;
674 shrink = hshrink = 1.0;
676 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
677 font_info->underwidth = [sfont underlineThickness];
678 font_info->size = font->pixel_size;
679 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
682 font_info->max_bounds.ascent =
683 lrint (hshrink * [sfont ascender] + expand * hd/2);
684 font_info->max_bounds.descent =
685 -lrint (hshrink* [sfont descender] - expand*hd/2);
687 font_info->max_bounds.ascent + font_info->max_bounds.descent;
688 font_info->max_bounds.width = lrint (font_info->width);
689 font_info->max_bounds.lbearing = lrint (brect.origin.x);
690 font_info->max_bounds.rbearing =
691 lrint (brect.size.width - font_info->width);
692 /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
695 /* set up synthItal and the CG font */
696 font_info->synthItal = synthItal;
698 ATSFontRef atsFont = ATSFontFindFromPostScriptName
699 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
701 if (atsFont == kATSFontRefUnspecified)
703 /* see if we can get it by dropping italic (then synthesizing) */
704 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
705 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
706 fontName], kATSOptionFlagsDefault);
707 if (atsFont != kATSFontRefUnspecified)
708 font_info->synthItal = YES;
711 /* last resort fallback */
712 atsFont = ATSFontFindFromPostScriptName
713 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
716 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
720 /* set up metrics portion of font struct */
721 font->ascent = [sfont ascender];
722 font->descent = -[sfont descender];
723 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
724 font->space_width = lrint (nsfont_char_width (sfont, ' '));
725 font->average_width = lrint (font_info->width);
726 font->max_width = lrint (font_info->max_bounds.width);
727 font->height = lrint (font_info->height);
728 font->underline_position = lrint (font_info->underpos);
729 font->underline_thickness = lrint (font_info->underwidth);
731 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
732 font->props[FONT_FULLNAME_INDEX] =
733 make_unibyte_string (font_info->name, strlen (font_info->name));
741 /* Close FONT on frame F. */
743 nsfont_close (FRAME_PTR f, struct font *font)
745 struct nsfont_info *font_info = (struct nsfont_info *)font;
748 /* FIXME: this occurs apparently due to same failure to detect same font
749 that causes need for cache in nsfont_open ()
750 (came after unicode-2 -> trunk) */
754 for (i =0; i<0x100; i++)
756 if (font_info->glyphs[i])
757 xfree (font_info->glyphs[i]);
758 if (font_info->metrics[i])
759 xfree (font_info->metrics[i]);
761 [font_info->nsfont release];
763 CGFontRelease (font_info->cgfont);
765 xfree (font_info->name);
770 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
771 return 1. If not, return 0. If a font must be opened to check
774 nsfont_has_char (Lisp_Object entity, int c)
780 /* Return a glyph code of FONT for character C (Unicode code point).
781 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
783 nsfont_encode_char (struct font *font, int c)
785 struct nsfont_info *font_info = (struct nsfont_info *)font;
786 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
790 return FONT_INVALID_CODE;
792 /* did we already cache this block? */
793 if (!font_info->glyphs[high])
794 ns_uni_to_glyphs (font_info, high);
796 g = font_info->glyphs[high][low];
797 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
798 return g == 0xFFFF ? FONT_INVALID_CODE : g;
802 /* Perform the size computation of glyphs of FONT and fill in members
803 of METRICS. The glyphs are specified by their glyph codes in
804 CODE (length NGLYPHS). */
806 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
807 struct font_metrics *metrics)
809 struct nsfont_info *font_info = (struct nsfont_info *)font;
810 struct font_metrics *pcm;
811 unsigned char high, low;
815 bzero (metrics, sizeof (struct font_metrics));
817 for (i =0; i<nglyphs; i++)
819 /* get metrics for this glyph, filling cache if need be */
820 /* TODO: get metrics for whole string from an NSLayoutManager
822 high = (code[i] & 0xFF00) >> 8;
823 low = code[i] & 0x00FF;
824 if (!font_info->metrics[high])
825 ns_glyph_metrics (font_info, high);
826 pcm = &(font_info->metrics[high][low]);
828 if (metrics->lbearing > totalWidth + pcm->lbearing)
829 metrics->lbearing = totalWidth + pcm->lbearing;
830 if (metrics->rbearing < totalWidth + pcm->rbearing)
831 metrics->rbearing = totalWidth + pcm->rbearing;
832 if (metrics->ascent < pcm->ascent)
833 metrics->ascent = pcm->ascent;
834 if (metrics->descent < pcm->descent)
835 metrics->descent = pcm->descent;
837 totalWidth += pcm->width;
840 metrics->width = totalWidth;
842 return totalWidth; /* not specified in doc, but xfont.c does it */
846 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
847 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
848 is nonzero, fill the background in advance. It is assured that
849 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
851 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
853 /* NOTE: focus and clip must be set
854 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
856 static char cbuf[1024];
858 #ifdef NS_IMPL_GNUSTEP
859 static float advances[1024];
860 float *adv = advances;
862 static CGSize advances[1024];
863 CGSize *adv = advances;
867 struct nsfont_info *font = ns_tmp_font;
868 NSColor *col, *bgCol;
869 unsigned short *t = s->char2b;
872 /* Select face based on input flags */
873 switch (ns_tmp_flags)
875 case NS_DUMPGLYPH_CURSOR:
878 case NS_DUMPGLYPH_MOUSEFACE:
879 face = FACE_FROM_ID (s->f,
880 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
882 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
889 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
890 r.origin.x += abs (s->face->box_line_width);
893 r.size.height = FONT_HEIGHT (font);
895 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
896 NS to render the string, it will come out differently from the individual
897 character widths added up because of layout processing. */
900 int cwidth, twidth = 0;
902 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
903 /* FIXME: composition: no vertical displacement is considered. */
904 t += s->cmp_from; /* advance into composition */
905 for (i = s->cmp_from; i < s->nchars; i++, t++)
907 hi = (*t & 0xFF00) >> 8;
911 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
915 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
916 ns_glyph_metrics (font, hi);
917 cwidth = font->metrics[hi][lo].width;
920 #ifdef NS_IMPL_GNUSTEP
922 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
924 (*adv++).width = cwidth;
927 len = adv - advances;
928 r.size.width = twidth;
932 /* fill background if requested */
936 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
937 int mbox_line_width = max (s->face->box_line_width, 0);
939 if (s->row->full_width_p)
941 if (br.origin.x <= fibw + 1 + mbox_line_width)
943 br.size.width += br.origin.x - mbox_line_width;
944 br.origin.x = mbox_line_width;
946 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
948 br.size.width += fibw;
950 if (s->face->box == FACE_NO_BOX)
952 /* expand unboxed top row over internal border */
953 if (br.origin.y <= fibw + 1 + mbox_line_width)
955 br.size.height += br.origin.y;
961 int correction = abs (s->face->box_line_width)+1;
962 br.origin.y += correction;
963 br.size.height -= 2*correction;
964 br.origin.x += correction;
965 br.size.width -= 2*correction;
968 if (!s->face->stipple)
969 [(NS_FACE_BACKGROUND (face) != 0
970 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
971 : FRAME_BACKGROUND_COLOR (s->f)) set];
974 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
975 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
981 /* set up for character rendering */
982 r.origin.y += font->voffset + (s->height - font->height)/2;
984 col = (NS_FACE_FOREGROUND (face) != 0
985 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
986 : FRAME_FOREGROUND_COLOR (s->f));
987 /* FIXME: find another way to pass this */
988 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
989 : (NS_FACE_BACKGROUND (face) != 0
990 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
991 : FRAME_BACKGROUND_COLOR (s->f)));
993 /* render under GNUstep using DPS */
994 #ifdef NS_IMPL_GNUSTEP
996 NSGraphicsContext *context = GSCurrentContext ();
1001 /* do erase if "foreground" mode */
1005 DPSmoveto (context, r.origin.x, r.origin.y);
1006 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1007 DPSxshow (context, cbuf, advances, len);
1008 DPSstroke (context);
1010 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1014 if (face->underline_p)
1016 if (face->underline_color != 0)
1017 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1020 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1021 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1022 if (face->underline_color != 0)
1028 /* draw with DPSxshow () */
1029 DPSmoveto (context, r.origin.x, r.origin.y);
1030 DPSxshow (context, cbuf, advances, len);
1031 DPSstroke (context);
1033 DPSgrestore (context);
1037 #else /* NS_IMPL_COCOA */
1039 CGContextRef gcontext =
1040 [[NSGraphicsContext currentContext] graphicsPort];
1041 static CGAffineTransform fliptf;
1042 static BOOL firstTime = YES;
1047 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1050 CGContextSaveGState (gcontext);
1052 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1054 CGContextSetFont (gcontext, font->cgfont);
1055 CGContextSetFontSize (gcontext, font->size);
1056 if (ns_antialias_text == NO || font->size <= ns_antialias_threshold)
1057 CGContextSetShouldAntialias (gcontext, 0);
1059 CGContextSetShouldAntialias (gcontext, 1);
1060 if (EQ (ns_use_qd_smoothing, Qt))
1061 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1063 CGContextSetTextMatrix (gcontext, fliptf);
1067 /* foreground drawing; erase first to avoid overstrike */
1069 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1070 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1071 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1072 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1075 if (face->underline_p)
1077 if (face->underline_color != 0)
1078 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1081 CGContextBeginPath (gcontext);
1082 CGContextMoveToPoint (gcontext,
1083 r.origin.x, r.origin.y + font->underpos);
1084 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1085 r.origin.y + font->underpos);
1086 CGContextStrokePath (gcontext);
1087 if (face->underline_color != 0)
1093 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1094 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1097 if (face->overstrike)
1099 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1100 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1104 CGContextRestoreGState (gcontext);
1107 #endif /* NS_IMPL_COCOA */
1112 /* Auto-creates a fontset built around the font in font_object,
1113 by creating an attributed string with characters from each
1114 script, then requesting the NS text system to fix attributes
1116 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1118 Lisp_Object script, famAndReg;
1119 struct nsfont_info *font_info =
1120 (struct nsfont_info *)XFONT_OBJECT (font_object);
1122 /* NS text system (and char buf) init */
1123 static NSTextStorage *store;
1124 static NSLayoutManager *layout;
1125 static NSRange range;
1126 static NSMutableDictionary *attribs;
1127 static Lisp_Object *scripts;
1128 static int nscripts;
1129 static int *scriptsNchars;
1130 static BOOL firstTime = YES;
1131 Lisp_Object regString = build_string ("iso10646-1");
1134 if (firstTime == YES)
1136 nscripts = XINT (Flength (Vscript_representative_chars));
1137 scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1138 unsigned char *buf = malloc (4*nscripts*sizeof (char));
1139 Lisp_Object scriptsChars = Vscript_representative_chars;
1140 unsigned char *tpos = buf;
1142 scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1144 for (i =0; i<nscripts; i++)
1146 Lisp_Object sChars = XCAR (scriptsChars);
1147 Lisp_Object chars = XCDR (sChars);
1148 unsigned int ch, c =0;
1149 scripts[i] = XCAR (sChars);
1151 while (CONSP (chars))
1153 ch = XUINT (XCAR (chars));
1154 chars = XCDR (chars);
1155 CHAR_STRING_ADVANCE (ch, tpos);
1158 scriptsNchars[i] = c;
1160 scriptsChars = XCDR (scriptsChars);
1164 store = [[NSTextStorage alloc] init];
1165 layout = [[NSLayoutManager alloc] init];
1166 [store addLayoutManager: layout];
1169 [store beginEditing];
1170 [[store mutableString] appendString:
1171 [NSString stringWithUTF8String: buf]];
1175 range = NSMakeRange (0, [store length]);
1177 attribs = [[NSMutableDictionary alloc] init];
1182 [store beginEditing];
1183 [store removeAttribute: NSFontAttributeName range: range];
1184 [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1185 [store addAttributes: attribs range: range];
1190 NSMutableDictionary *map =
1191 [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1192 NSEnumerator *fonts;
1193 NSFont *cfont = nil, *tfont;
1197 for (i =0; i<nscripts; i++)
1199 [map removeAllObjects];
1200 for (j =0; j<scriptsNchars[i]; j++)
1202 cfont = [store attribute: NSFontAttributeName atIndex: idx++
1203 effectiveRange: NULL];
1204 n = [map objectForKey: cfont];
1206 n = [NSNumber numberWithInt: 1];
1208 n = [NSNumber numberWithInt: [n intValue] + 1];
1209 [map setObject: n forKey: cfont];
1212 /* majority rules */
1214 fonts = [map keyEnumerator];
1215 while (tfont = [fonts nextObject])
1217 n = [map objectForKey: tfont];
1218 if ([n intValue] > max)
1227 char *family = strdup([[cfont familyName] UTF8String]);
1228 Lisp_Object famAndReg;
1230 nsfont_escape_name (family);
1231 famAndReg = Fcons (build_string (family), regString);
1234 fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1235 font_info->name, family,
1236 SDATA (SYMBOL_NAME (scripts[i])));
1238 Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1243 fprintf (stderr, "%s fontset: none found for script '%s'\n",
1244 font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1246 } /* for i = script */
1252 /* ==========================================================================
1254 Font glyph and metrics caching functions
1256 ========================================================================== */
1258 /* Find and cache corresponding glyph codes for unicode values in given
1259 hi-byte block of 256. */
1261 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1263 #ifdef NS_IMPL_COCOA
1264 static EmacsGlyphStorage *glyphStorage;
1265 static char firstTime = 1;
1267 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1268 unsigned int i, g, idx;
1269 unsigned short *glyphs;
1272 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1277 #ifdef NS_IMPL_COCOA
1281 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1285 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1286 if (!unichars || !(font_info->glyphs[block]))
1289 /* create a string containing all unicode characters in this block */
1290 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1291 if (idx < 0xD800 || idx > 0xDFFF)
1294 unichars[i] = 0xFEFF;
1295 unichars[0x100] = 0;
1298 #ifdef NS_IMPL_COCOA
1299 NSString *allChars = [[NSString alloc]
1300 initWithCharactersNoCopy: unichars
1303 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1304 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1305 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1306 unsigned int gInd =0, cInd =0;
1308 [glyphStorage setString: allChars font: font_info->nsfont];
1309 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1310 desiredNumberOfCharacters: glyphStorage->maxChar
1311 glyphIndex: &gInd characterIndex: &cInd];
1313 glyphs = font_info->glyphs[block];
1314 for (i =0; i<0x100; i++, glyphs++)
1316 #ifdef NS_IMPL_GNUSTEP
1319 g = glyphStorage->cglyphs[i];
1320 /* TODO: is this a good check? maybe need to use coveredChars.. */
1322 g = 0xFFFF; /* hopefully unused... */
1327 #ifdef NS_IMPL_COCOA
1337 /* Determine and cache metrics for corresponding glyph codes in given
1338 hi-byte block of 256. */
1340 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1343 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1345 struct font_metrics *metrics;
1348 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1351 #ifdef NS_IMPL_GNUSTEP
1352 /* not implemented yet (as of startup 0.18), so punt */
1354 numGlyphs = 0x10000;
1358 sfont = [font_info->nsfont screenFont];
1360 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1361 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1362 if (!(font_info->metrics[block]))
1365 metrics = font_info->metrics[block];
1366 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1369 NSRect r = [sfont boundingRectForGlyph: g];
1371 #ifdef NS_IMPL_GNUSTEP
1374 NSString *s = [NSString stringWithFormat: @"%c", g];
1375 w = [sfont widthOfString: s];
1378 w = [sfont advancementForGlyph: g].width;
1381 metrics->width = lrint (w);
1384 rb = r.size.width - w;
1386 metrics->lbearing = round (lb);
1387 if (font_info->ital)
1388 rb += 0.22 * font_info->height;
1389 metrics->rbearing = lrint (w + rb);
1391 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1392 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1393 metrics->ascent = r.size.height - metrics->descent;
1394 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1400 #ifdef NS_IMPL_COCOA
1401 /* helper for font glyph setup */
1402 @implementation EmacsGlyphStorage
1406 return [self initWithCapacity: 1024];
1409 - initWithCapacity: (unsigned long) c
1411 self = [super init];
1414 dict = [NSMutableDictionary new];
1415 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1428 - (void) setString: (NSString *)str font: (NSFont *)font
1430 [dict setObject: font forKey: NSFontAttributeName];
1431 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1432 maxChar = [str length];
1436 /* NSGlyphStorage protocol */
1437 - (unsigned int)layoutOptions
1442 - (NSAttributedString *)attributedString
1447 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1448 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1449 characterIndex: (unsigned int)charIndex
1451 len = glyphIndex+length;
1452 for (i =glyphIndex; i<len; i++)
1453 cglyphs[i] = glyphs[i-glyphIndex];
1458 - (void)setIntAttribute: (int)attributeTag value: (int)val
1459 forGlyphAtIndex: (unsigned)glyphIndex
1465 #endif /* NS_IMPL_COCOA */
1470 dump_glyphstring (struct glyph_string *s)
1474 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1475 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1476 s->row->overlapping_p, s->background_filled_p);
1477 for (i =0; i<s->nchars; i++)
1478 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1479 fprintf (stderr, "\n");
1487 nsfont_driver.type = Qns;
1488 register_font_driver (&nsfont_driver, NULL);
1489 DEFSYM (Qapple, "apple");
1490 DEFSYM (Qroman, "roman");
1491 DEFSYM (Qmedium, "medium");
1494 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae