1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006-2012 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"
41 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
42 #ifdef NS_IMPL_GNUSTEP
43 #import <AppKit/NSFontDescriptor.h>
46 #define NSFONT_TRACE 0
48 extern Lisp_Object Qns;
49 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
50 static Lisp_Object Qapple, Qroman, Qmedium;
51 extern Lisp_Object Qappend;
52 extern float ns_antialias_threshold;
53 extern int ns_tmp_flags;
54 extern struct nsfont_info *ns_tmp_font;
56 /* font glyph and metrics caching functions, implemented at end */
57 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
59 static void ns_glyph_metrics (struct nsfont_info *font_info,
63 /* ==========================================================================
67 ========================================================================== */
70 /* Replace spaces w/another character so emacs core font parsing routines
73 ns_escape_name (char *name)
75 int i =0, len =strlen (name);
82 /* Reconstruct spaces in a font family name passed through emacs. */
84 ns_unescape_name (char *name)
86 int i =0, len =strlen (name);
93 /* Extract family name from a font spec. */
95 ns_get_family (Lisp_Object font_spec)
97 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
102 char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
104 ns_unescape_name (tmp);
105 family = [NSString stringWithUTF8String: tmp];
112 /* Return 0 if attr not set, else value (which might also be 0).
113 On Leopard 0 gets returned even on descriptors where the attribute
114 was never set, so there's no way to distinguish between unspecified
115 and set to not have. Callers should assume 0 means unspecified. */
117 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
119 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
120 NSNumber *val = [tdict objectForKey: trait];
121 return val == nil ? 0.0 : [val floatValue];
125 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
126 to NSFont descriptor. Information under extra only needed for matching. */
127 #define STYLE_REF 100
128 static NSFontDescriptor *
129 ns_spec_to_descriptor (Lisp_Object font_spec)
131 NSFontDescriptor *fdesc;
132 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
133 NSMutableDictionary *tdict = [NSMutableDictionary new];
134 NSString *family = ns_get_family (font_spec);
137 /* add each attr in font_spec to fdAttrs.. */
138 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
139 if (n != -1 && n != STYLE_REF)
140 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
141 forKey: NSFontWeightTrait];
142 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
143 if (n != -1 && n != STYLE_REF)
144 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
145 forKey: NSFontSlantTrait];
146 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
147 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
148 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
149 forKey: NSFontWidthTrait];
150 if ([tdict count] > 0)
151 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
153 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
156 fdesc = [fdesc fontDescriptorWithFamily: family];
165 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
167 ns_descriptor_to_entity (NSFontDescriptor *desc,
171 Lisp_Object font_entity = font_make_entity ();
172 /* NSString *psName = [desc postscriptName]; */
173 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
174 unsigned int traits = [desc symbolicTraits];
177 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
179 family = [desc objectForKey: NSFontNameAttribute];
181 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
183 escapedFamily = xstrdup ([family UTF8String]);
184 ns_escape_name (escapedFamily);
186 ASET (font_entity, FONT_TYPE_INDEX, Qns);
187 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
188 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
189 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
190 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
192 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
193 traits & NSFontBoldTrait ? Qbold : Qmedium);
194 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
195 make_number (100 + 100
196 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
197 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
198 traits & NSFontItalicTrait ? Qitalic : Qnormal);
199 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
200 make_number (100 + 100
201 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
202 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
203 traits & NSFontCondensedTrait ? Qcondensed :
204 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
205 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
206 make_number (100 + 100
207 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
209 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
210 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
211 ASET (font_entity, FONT_SPACING_INDEX,
212 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
213 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
215 ASET (font_entity, FONT_EXTRA_INDEX, extra);
216 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
220 fprintf (stderr, "created font_entity:\n ");
221 debug_print (font_entity);
224 xfree (escapedFamily);
229 /* Default font entity. */
231 ns_fallback_entity (void)
233 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
234 fontDescriptor], Qnil, NULL);
238 /* Utility: get width of a char c in screen font SFONT */
240 ns_char_width (NSFont *sfont, int c)
243 NSString *cstr = [NSString stringWithFormat: @"%c", c];
246 NSGlyph glyph = [sfont glyphWithName: cstr];
248 w = [sfont advancementForGlyph: glyph].width;
253 NSDictionary *attrsDictionary =
254 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
255 w = [cstr sizeWithAttributes: attrsDictionary].width;
261 /* Return average width over ASCII printable characters for SFONT. */
263 static NSString *ascii_printable;
266 ns_ascii_average_width (NSFont *sfont)
270 if (!ascii_printable)
274 for (ch = 0; ch < 95; ch++)
275 chars[ch] = ' ' + ch;
278 ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
282 NSGlyph glyph = [sfont glyphWithName: ascii_printable];
284 w = [sfont advancementForGlyph: glyph].width;
289 NSDictionary *attrsDictionary =
290 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
291 w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
294 return lrint (w / 95.0);
298 /* Return whether set1 covers set2 to a reasonable extent given by pct.
299 We check, out of each 16 Unicode char range containing chars in set2,
300 whether at least one character is present in set1.
301 This must be true for pct of the pairs to consider it covering. */
303 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
305 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
306 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
307 int i, off = 0, tot = 0;
309 /* Work around what appears to be a GNUstep bug.
310 See <http://bugs.gnu.org/11853>. */
311 if (! (bytes1 && bytes2))
314 for (i=0; i<4096; i++, bytes1++, bytes2++)
318 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
321 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
322 return (float)off / tot < 1.0 - pct;
326 /* Convert :lang property to a script. Use of :lang property by font backend
327 seems to be limited for now (2009/05) to ja, zh, and ko. */
329 *ns_lang_to_script (Lisp_Object lang)
331 if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
333 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
334 have more characters. */
335 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
337 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
344 /* Convert OTF 4-letter script code to emacs script name. (Why can't
345 everyone just use some standard Unicode names for these?) */
347 *ns_otf_to_script (Lisp_Object otf)
349 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
350 return CONSP (script)
351 ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
356 /* Convert a font registry, such as */
358 *ns_registry_to_script (char *reg)
360 Lisp_Object script, r, rts = Vns_reg_to_script;
363 r = XCAR (XCAR (rts));
364 if (!strncmp(SSDATA(r), reg, strlen(SSDATA(r))))
366 script = XCDR (XCAR (rts));
367 return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
375 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
376 plus registry regular property, for something that can be mapped to a
377 Unicode script. Empty string returned if no script spec found. */
379 *ns_get_req_script (Lisp_Object font_spec)
381 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
382 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
384 /* The extra-bundle properties have priority. */
385 for ( ; CONSP (extra); extra = XCDR (extra))
387 Lisp_Object tmp = XCAR (extra);
390 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
391 if (EQ (key, QCscript) && SYMBOLP (val))
392 return [NSString stringWithUTF8String:
393 SSDATA (SYMBOL_NAME (val))];
394 if (EQ (key, QClang) && SYMBOLP (val))
395 return ns_lang_to_script (val);
396 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
397 return ns_otf_to_script (val);
401 /* If we get here, check the charset portion of the registry. */
404 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
405 (which causes box rendering if we don't treat it like iso8858-1)
406 but also for ascii (which causes unnecessary font substitution). */
408 if (EQ (reg, Qiso10646_1))
411 return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
418 /* This small function is static in fontset.c. If it can be made public for
419 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
421 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
423 if (EQ (XCAR (arg), val))
426 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
428 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
433 /* Use the Unicode range information in Vchar_script_table to convert a script
434 name into an NSCharacterSet. */
435 static NSCharacterSet
436 *ns_script_to_charset (NSString *scriptName)
438 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
439 Lisp_Object script = intern ([scriptName UTF8String]);
440 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
442 if (! NILP (Fmemq (script, script_list)))
444 Lisp_Object ranges, range_list;
446 ranges = Fcons (script, Qnil);
447 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
449 range_list = Fnreverse (XCDR (ranges));
450 if (! NILP (range_list))
452 for (; CONSP (range_list); range_list = XCDR (range_list))
454 int start = XINT (XCAR (XCAR (range_list)));
455 int end = XINT (XCDR (XCAR (range_list)));
457 debug_print (XCAR (range_list));
459 [charset addCharactersInRange:
460 NSMakeRange (start, end-start)];
468 /* Return an array of font families containing characters for the given
469 script, for the given coverage criterion, including at least LastResort.
470 Results are cached by script for faster access.
471 If none are found, we reduce the percentage and try again, until 5%.
472 This provides a font with at least some characters if such can be found.
473 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
474 (b) need approximate match as fonts covering full Unicode ranges are rare. */
476 *ns_get_covering_families (NSString *script, float pct)
478 static NSMutableDictionary *scriptToFamilies = nil;
479 NSMutableSet *families;
482 NSLog(@"Request covering families for script: '%@'", script);
484 if (scriptToFamilies == nil)
485 scriptToFamilies = [[NSMutableDictionary alloc] init];
487 if ((families = [scriptToFamilies objectForKey: script]) == nil)
489 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
490 NSArray *allFamilies = [fontMgr availableFontFamilies];
492 if ([script length] == 0)
493 families = [NSMutableSet setWithArray: allFamilies];
496 NSCharacterSet *charset = ns_script_to_charset (script);
498 families = [NSMutableSet setWithCapacity: 10];
501 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
502 while ((family = [allFamiliesEnum nextObject]))
504 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
505 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
506 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
508 fset = [NSCharacterSet characterSetWithRange:
509 NSMakeRange (0, 127)];
510 if (ns_charset_covers(fset, charset, pct))
511 [families addObject: family];
514 if ([families count] > 0 || pct < 0.05)
520 if ([families count] == 0)
521 [families addObject: @"LastResort"];
523 [scriptToFamilies setObject: families forKey: script];
527 NSLog(@" returning %d families", [families count]);
532 /* Implementation for list() and match(). List() can return nil, match()
533 must return something. Strategy is to drop family name from attribute
534 matching set for match. */
536 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
538 Lisp_Object tem, list = Qnil;
539 NSFontDescriptor *fdesc, *desc;
541 NSArray *matchingDescs;
549 fprintf (stderr, "nsfont: %s for fontspec:\n ",
550 (isMatch ? "match" : "list"));
551 debug_print (font_spec);
554 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
556 fdesc = ns_spec_to_descriptor (font_spec);
557 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
559 [fkeys removeObject: NSFontFamilyAttribute];
561 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
563 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
564 [matchingDescs count]);
566 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
568 if (![cFamilies containsObject:
569 [desc objectForKey: NSFontFamilyAttribute]])
571 tem = ns_descriptor_to_entity (desc,
572 AREF (font_spec, FONT_EXTRA_INDEX),
576 list = Fcons (tem, list);
577 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
581 /* Add synthItal member if needed. */
582 family = [fdesc objectForKey: NSFontFamilyAttribute];
583 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
585 NSFontDescriptor *s1 = [NSFontDescriptor new];
586 NSFontDescriptor *sDesc
587 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
588 fontDescriptorWithFamily: family];
589 list = Fcons (ns_descriptor_to_entity (sDesc,
590 AREF (font_spec, FONT_EXTRA_INDEX),
595 /* Return something if was a match and nothing found. */
597 return ns_fallback_entity ();
600 fprintf (stderr, " Returning %"pI"d entities.\n",
601 XINT (Flength (list)));
608 /* ==========================================================================
610 Font driver implementation
612 ========================================================================== */
615 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
616 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
617 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
618 static Lisp_Object nsfont_list_family (Lisp_Object frame);
619 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
621 static void nsfont_close (FRAME_PTR f, struct font *font);
622 static int nsfont_has_char (Lisp_Object entity, int c);
623 static unsigned int nsfont_encode_char (struct font *font, int c);
624 static int nsfont_text_extents (struct font *font, unsigned int *code,
625 int nglyphs, struct font_metrics *metrics);
626 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
627 bool with_background);
629 struct font_driver nsfont_driver =
632 1, /* case sensitive */
637 NULL, /*free_entity */
640 NULL, /* prepare_face */
641 NULL, /* done_face */
646 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
647 anchor_point, otf_capability, otf_driver,
648 start_for_frame, end_for_frame, shape */
652 /* Return a cache of font-entities on FRAME. The cache must be a
653 cons whose cdr part is the actual cache area. */
655 nsfont_get_cache (FRAME_PTR frame)
657 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
658 return (dpyinfo->name_list_element);
662 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
663 **list** of font-entities. This and match () are sole APIs that allocate
664 font-entities. Properties to be considered (2009/05/19) are:
665 regular: foundry, family, adstyle, registry
666 extended: script, lang, otf
667 "Extended" properties are not part of the vector but get stored as
668 lisp properties under FONT_EXTRA_INDEX.
670 The returned entities should have type set (to 'ns), plus the following:
671 foundry, family, adstyle, registry,
672 weight, slant, width, size (0 if scalable),
673 dpi, spacing, avgwidth (0 if scalable) */
675 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
677 return ns_findfonts (font_spec, NO);
681 /* Return a font entity most closely matching with FONT_SPEC on
682 FRAME. The closeness is determined by the font backend, thus
683 `face-font-selection-order' is ignored here.
684 Properties to be considered are same as for list(). */
686 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
688 return ns_findfonts(font_spec, YES);
692 /* List available families. The value is a list of family names
695 nsfont_list_family (Lisp_Object frame)
697 Lisp_Object list = Qnil;
698 NSEnumerator *families =
699 [[[NSFontManager sharedFontManager] availableFontFamilies]
702 while ((family = [families nextObject]))
703 list = Fcons (intern ([family UTF8String]), list);
704 /* FIXME: escape the name? */
707 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
708 XINT (Flength (list)));
714 /* Open a font specified by FONT_ENTITY on frame F. If the font is
715 scalable, open it with PIXEL_SIZE. */
717 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
720 unsigned int traits = 0;
721 struct nsfont_info *font_info;
723 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
724 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
726 NSFont *nsfont, *sfont;
729 Lisp_Object font_object;
731 static NSMutableDictionary *fontCache = nil;
734 /* 2008/03/08: The same font may end up being requested for different
735 entities, due to small differences in numeric values or other issues,
736 or for different copies of the same entity. Therefore we cache to
737 avoid creating multiple struct font objects (with metrics cache, etc.)
738 for the same NSFont object. */
739 if (fontCache == nil)
740 fontCache = [[NSMutableDictionary alloc] init];
744 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
745 debug_print (font_entity);
750 /* try to get it out of frame params */
751 Lisp_Object tem = get_frame_param (f, Qfontsize);
752 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
755 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
756 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
758 family = ns_get_family (font_entity);
760 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
761 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
762 when setting family in ns_spec_to_descriptor(). */
763 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
764 traits |= NSBoldFontMask;
765 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
766 traits |= NSItalicFontMask;
768 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
769 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
770 nsfont = [fontMgr fontWithFamily: family
771 traits: traits weight: fixLeopardBug
773 /* if didn't find, try synthetic italic */
774 if (nsfont == nil && synthItal)
776 nsfont = [fontMgr fontWithFamily: family
777 traits: traits & ~NSItalicFontMask
778 weight: fixLeopardBug size: pixel_size];
781 /* LastResort not really a family */
782 if (nsfont == nil && [@"LastResort" isEqualToString: family])
783 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
788 message_with_string ("*** Warning: font in family '%s' not found",
789 build_string ([family UTF8String]), 1);
790 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
794 NSLog (@"%@\n", nsfont);
796 /* Check the cache */
797 cached = [fontCache objectForKey: nsfont];
798 if (cached != nil && !synthItal)
801 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
802 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
803 XHASH (font_object) = [cached unsignedLongValue];
808 font_object = font_make_object (VECSIZE (struct nsfont_info),
809 font_entity, pixel_size);
811 [fontCache setObject: [NSNumber numberWithUnsignedLong:
812 (unsigned long) XHASH (font_object)]
816 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
817 font = (struct font *) font_info;
819 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
821 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
822 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
827 sfont = [nsfont screenFont];
831 /* non-metric backend font struct fields */
832 font = (struct font *) font_info;
833 font->pixel_size = [sfont pointSize];
834 font->driver = &nsfont_driver;
835 font->encoding_charset = -1;
836 font->repertory_charset = -1;
837 font->default_ascent = 0;
838 font->vertical_centering = 0;
839 font->baseline_offset = 0;
840 font->relative_compose = 0;
841 font->font_encoder = NULL;
843 font->props[FONT_FORMAT_INDEX] = Qns;
844 font->props[FONT_FILE_INDEX] = Qnil;
847 const char *fontName = [[nsfont fontName] UTF8String];
849 /* The values specified by fonts are not always exact. For
850 * example, a 6x8 font could specify that the descender is
851 * -2.00000405... (represented by 0xc000000220000000). Without
852 * adjustment, the code below would round the descender to -3,
853 * resulting in a font that would be one pixel higher than
855 CGFloat adjusted_descender = [sfont descender] + 0.0001;
857 #ifdef NS_IMPL_GNUSTEP
858 font_info->nsfont = sfont;
860 font_info->nsfont = nsfont;
862 [font_info->nsfont retain];
864 /* set up ns_font (defined in nsgui.h) */
865 font_info->name = xstrdup (fontName);
866 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
868 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
870 /* Metrics etc.; some fonts return an unusually large max advance, so we
871 only use it for fonts that have wide characters. */
872 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
873 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
875 brect = [sfont boundingRectForFont];
877 font_info->underpos = [sfont underlinePosition];
878 font_info->underwidth = [sfont underlineThickness];
879 font_info->size = font->pixel_size;
882 font_info->max_bounds.ascent = lrint ([sfont ascender]);
883 /* Descender is usually negative. Use floor to avoid
884 clipping descenders. */
885 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
887 font_info->max_bounds.ascent + font_info->max_bounds.descent;
888 font_info->max_bounds.width = lrint (font_info->width);
889 font_info->max_bounds.lbearing = lrint (brect.origin.x);
890 font_info->max_bounds.rbearing =
891 lrint (brect.size.width - font_info->width);
894 /* set up synthItal and the CG font */
895 font_info->synthItal = synthItal;
897 ATSFontRef atsFont = ATSFontFindFromPostScriptName
898 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
900 if (atsFont == kATSFontRefUnspecified)
902 /* see if we can get it by dropping italic (then synthesizing) */
903 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
904 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
905 fontName], kATSOptionFlagsDefault);
906 if (atsFont != kATSFontRefUnspecified)
907 font_info->synthItal = YES;
910 /* last resort fallback */
911 atsFont = ATSFontFindFromPostScriptName
912 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
915 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
919 /* set up metrics portion of font struct */
920 font->ascent = lrint([sfont ascender]);
921 font->descent = -lrint(floor(adjusted_descender));
922 font->space_width = lrint (ns_char_width (sfont, ' '));
923 font->max_width = lrint (font_info->max_bounds.width);
924 font->min_width = font->space_width; /* Approximate. */
925 font->average_width = ns_ascii_average_width (sfont);
927 font->height = lrint (font_info->height);
928 font->underline_position = lrint (font_info->underpos);
929 font->underline_thickness = lrint (font_info->underwidth);
931 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
932 font->props[FONT_FULLNAME_INDEX] =
933 make_unibyte_string (font_info->name, strlen (font_info->name));
941 /* Close FONT on frame F. */
943 nsfont_close (FRAME_PTR f, struct font *font)
945 struct nsfont_info *font_info = (struct nsfont_info *)font;
948 /* FIXME: this occurs apparently due to same failure to detect same font
949 that causes need for cache in nsfont_open () */
953 for (i =0; i<0x100; i++)
955 xfree (font_info->glyphs[i]);
956 xfree (font_info->metrics[i]);
958 [font_info->nsfont release];
960 CGFontRelease (font_info->cgfont);
962 xfree (font_info->name);
967 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
968 return 1. If not, return 0. If a font must be opened to check
971 nsfont_has_char (Lisp_Object entity, int c)
977 /* Return a glyph code of FONT for character C (Unicode code point).
978 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
980 nsfont_encode_char (struct font *font, int c)
982 struct nsfont_info *font_info = (struct nsfont_info *)font;
983 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
987 return FONT_INVALID_CODE;
989 /* did we already cache this block? */
990 if (!font_info->glyphs[high])
991 ns_uni_to_glyphs (font_info, high);
993 g = font_info->glyphs[high][low];
994 return g == 0xFFFF ? FONT_INVALID_CODE : g;
998 /* Perform the size computation of glyphs of FONT and fill in members
999 of METRICS. The glyphs are specified by their glyph codes in
1000 CODE (length NGLYPHS). */
1002 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
1003 struct font_metrics *metrics)
1005 struct nsfont_info *font_info = (struct nsfont_info *)font;
1006 struct font_metrics *pcm;
1007 unsigned char high, low;
1011 memset (metrics, 0, sizeof (struct font_metrics));
1013 for (i =0; i<nglyphs; i++)
1015 /* get metrics for this glyph, filling cache if need be */
1016 /* TODO: get metrics for whole string from an NSLayoutManager
1017 (if not too slow) */
1018 high = (code[i] & 0xFF00) >> 8;
1019 low = code[i] & 0x00FF;
1020 if (!font_info->metrics[high])
1021 ns_glyph_metrics (font_info, high);
1022 pcm = &(font_info->metrics[high][low]);
1024 if (metrics->lbearing > totalWidth + pcm->lbearing)
1025 metrics->lbearing = totalWidth + pcm->lbearing;
1026 if (metrics->rbearing < totalWidth + pcm->rbearing)
1027 metrics->rbearing = totalWidth + pcm->rbearing;
1028 if (metrics->ascent < pcm->ascent)
1029 metrics->ascent = pcm->ascent;
1030 if (metrics->descent < pcm->descent)
1031 metrics->descent = pcm->descent;
1033 totalWidth += pcm->width;
1036 metrics->width = totalWidth;
1038 return totalWidth; /* not specified in doc, but xfont.c does it */
1042 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1043 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1044 fill the background in advance. It is assured that WITH_BACKGROUND
1045 is false when (FROM > 0 || TO < S->nchars). */
1047 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1048 bool with_background)
1049 /* NOTE: focus and clip must be set
1050 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1052 static char cbuf[1024];
1054 #ifdef NS_IMPL_GNUSTEP
1055 static float advances[1024];
1056 float *adv = advances;
1058 static CGSize advances[1024];
1059 CGSize *adv = advances;
1063 struct nsfont_info *font = ns_tmp_font;
1064 NSColor *col, *bgCol;
1065 unsigned short *t = s->char2b;
1067 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1068 int end = isComposite ? s->cmp_to : s->nchars;
1070 /* Select face based on input flags */
1071 switch (ns_tmp_flags)
1073 case NS_DUMPGLYPH_CURSOR:
1076 case NS_DUMPGLYPH_MOUSEFACE:
1077 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1079 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1086 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1087 r.origin.x += abs (s->face->box_line_width);
1090 r.size.height = FONT_HEIGHT (font);
1092 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1093 NS to render the string, it will come out differently from the individual
1094 character widths added up because of layout processing. */
1096 int cwidth, twidth = 0;
1098 /* FIXME: composition: no vertical displacement is considered. */
1099 t += s->cmp_from; /* advance into composition */
1100 for (i = s->cmp_from; i < end; i++, t++)
1102 hi = (*t & 0xFF00) >> 8;
1106 if (!s->first_glyph->u.cmp.automatic)
1107 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1110 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1111 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1112 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1113 cwidth = LGLYPH_WIDTH (glyph);
1116 cwidth = LGLYPH_WADJUST (glyph);
1117 #ifdef NS_IMPL_GNUSTEP
1118 *(adv-1) += LGLYPH_XOFF (glyph);
1120 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1127 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1128 ns_glyph_metrics (font, hi);
1129 cwidth = font->metrics[hi][lo].width;
1132 #ifdef NS_IMPL_GNUSTEP
1134 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1136 (*adv++).width = cwidth;
1139 len = adv - advances;
1140 r.size.width = twidth;
1144 /* fill background if requested */
1145 if (with_background && !isComposite)
1148 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1149 int mbox_line_width = max (s->face->box_line_width, 0);
1151 if (s->row->full_width_p)
1153 if (br.origin.x <= fibw + 1 + mbox_line_width)
1155 br.size.width += br.origin.x - mbox_line_width;
1156 br.origin.x = mbox_line_width;
1158 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1160 br.size.width += fibw;
1162 if (s->face->box == FACE_NO_BOX)
1164 /* expand unboxed top row over internal border */
1165 if (br.origin.y <= fibw + 1 + mbox_line_width)
1167 br.size.height += br.origin.y;
1173 int correction = abs (s->face->box_line_width)+1;
1174 br.origin.y += correction;
1175 br.size.height -= 2*correction;
1176 br.origin.x += correction;
1177 br.size.width -= 2*correction;
1180 if (!s->face->stipple)
1181 [(NS_FACE_BACKGROUND (face) != 0
1182 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1183 : FRAME_BACKGROUND_COLOR (s->f)) set];
1186 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1187 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1193 /* set up for character rendering */
1194 r.origin.y = s->ybase;
1196 col = (NS_FACE_FOREGROUND (face) != 0
1197 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1198 : FRAME_FOREGROUND_COLOR (s->f));
1199 /* FIXME: find another way to pass this */
1200 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1201 : (NS_FACE_BACKGROUND (face) != 0
1202 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1203 : FRAME_BACKGROUND_COLOR (s->f)));
1205 /* render under GNUstep using DPS */
1206 #ifdef NS_IMPL_GNUSTEP
1208 NSGraphicsContext *context = GSCurrentContext ();
1213 /* do erase if "foreground" mode */
1217 DPSmoveto (context, r.origin.x, r.origin.y);
1218 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1219 DPSxshow (context, cbuf, advances, len);
1220 DPSstroke (context);
1222 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1227 /* draw with DPSxshow () */
1228 DPSmoveto (context, r.origin.x, r.origin.y);
1229 DPSxshow (context, cbuf, advances, len);
1230 DPSstroke (context);
1232 DPSgrestore (context);
1235 #else /* NS_IMPL_COCOA */
1237 CGContextRef gcontext =
1238 [[NSGraphicsContext currentContext] graphicsPort];
1239 static CGAffineTransform fliptf;
1240 static BOOL firstTime = YES;
1245 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1248 CGContextSaveGState (gcontext);
1250 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1252 CGContextSetFont (gcontext, font->cgfont);
1253 CGContextSetFontSize (gcontext, font->size);
1254 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1255 CGContextSetShouldAntialias (gcontext, 0);
1257 CGContextSetShouldAntialias (gcontext, 1);
1259 CGContextSetTextMatrix (gcontext, fliptf);
1263 /* foreground drawing; erase first to avoid overstrike */
1265 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1266 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1267 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1268 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1273 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1274 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1277 if (face->overstrike)
1279 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1280 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1284 CGContextRestoreGState (gcontext);
1286 #endif /* NS_IMPL_COCOA */
1288 /* Draw underline, overline, strike-through. */
1289 ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1296 /* ==========================================================================
1298 Font glyph and metrics caching functions
1300 ========================================================================== */
1302 /* Find and cache corresponding glyph codes for unicode values in given
1303 hi-byte block of 256. */
1305 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1307 #ifdef NS_IMPL_COCOA
1308 static EmacsGlyphStorage *glyphStorage;
1309 static char firstTime = 1;
1311 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1312 unsigned int i, g, idx;
1313 unsigned short *glyphs;
1316 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1321 #ifdef NS_IMPL_COCOA
1325 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1329 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1330 if (!unichars || !(font_info->glyphs[block]))
1333 /* create a string containing all Unicode characters in this block */
1334 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1335 if (idx < 0xD800 || idx > 0xDFFF)
1338 unichars[i] = 0xFEFF;
1339 unichars[0x100] = 0;
1342 #ifdef NS_IMPL_COCOA
1343 NSString *allChars = [[NSString alloc]
1344 initWithCharactersNoCopy: unichars
1347 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1348 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1349 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1350 NSUInteger gInd = 0, cInd = 0;
1352 [glyphStorage setString: allChars font: font_info->nsfont];
1353 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1354 desiredNumberOfCharacters: glyphStorage->maxChar
1355 glyphIndex: &gInd characterIndex: &cInd];
1357 glyphs = font_info->glyphs[block];
1358 for (i = 0; i < 0x100; i++, glyphs++)
1360 #ifdef NS_IMPL_GNUSTEP
1363 g = glyphStorage->cglyphs[i];
1364 /* TODO: is this a good check? maybe need to use coveredChars.. */
1366 g = 0xFFFF; /* hopefully unused... */
1371 #ifdef NS_IMPL_COCOA
1381 /* Determine and cache metrics for corresponding glyph codes in given
1382 hi-byte block of 256. */
1384 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1387 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1389 struct font_metrics *metrics;
1392 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1395 #ifdef NS_IMPL_GNUSTEP
1396 /* not implemented yet (as of startup 0.18), so punt */
1398 numGlyphs = 0x10000;
1402 sfont = [font_info->nsfont screenFont];
1404 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1405 if (!(font_info->metrics[block]))
1408 metrics = font_info->metrics[block];
1409 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1412 NSRect r = [sfont boundingRectForGlyph: g];
1414 w = max ([sfont advancementForGlyph: g].width, 2.0);
1415 metrics->width = lrint (w);
1418 rb = r.size.width - w;
1420 metrics->lbearing = round (lb);
1421 if (font_info->ital)
1422 rb += 0.22 * font_info->height;
1423 metrics->rbearing = lrint (w + rb);
1425 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1426 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1427 metrics->ascent = r.size.height - metrics->descent;
1428 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1434 #ifdef NS_IMPL_COCOA
1435 /* helper for font glyph setup */
1436 @implementation EmacsGlyphStorage
1440 return [self initWithCapacity: 1024];
1443 - initWithCapacity: (unsigned long) c
1445 self = [super init];
1448 dict = [NSMutableDictionary new];
1449 cglyphs = xmalloc (c * sizeof (CGGlyph));
1462 - (void) setString: (NSString *)str font: (NSFont *)font
1464 [dict setObject: font forKey: NSFontAttributeName];
1467 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1468 maxChar = [str length];
1472 /* NSGlyphStorage protocol */
1473 - (NSUInteger)layoutOptions
1478 - (NSAttributedString *)attributedString
1483 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1484 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1485 characterIndex: (NSUInteger)charIndex
1487 len = glyphIndex+length;
1488 for (i =glyphIndex; i<len; i++)
1489 cglyphs[i] = glyphs[i-glyphIndex];
1494 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1495 forGlyphAtIndex: (NSUInteger)glyphIndex
1501 #endif /* NS_IMPL_COCOA */
1506 ns_dump_glyphstring (struct glyph_string *s)
1510 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1511 "overlap = %d, bg_filled = %d:",
1512 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1513 s->row->overlapping_p, s->background_filled_p);
1514 for (i =0; i<s->nchars; i++)
1515 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1516 fprintf (stderr, "\n");
1521 syms_of_nsfont (void)
1523 nsfont_driver.type = Qns;
1524 register_font_driver (&nsfont_driver, NULL);
1525 DEFSYM (Qapple, "apple");
1526 DEFSYM (Qroman, "roman");
1527 DEFSYM (Qmedium, "medium");
1528 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1529 doc: /* Internal use: maps font registry to Unicode script. */);
1531 ascii_printable = NULL;