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;
57 /* font glyph and metrics caching functions, implemented at end */
58 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
60 static void ns_glyph_metrics (struct nsfont_info *font_info,
64 /* ==========================================================================
68 ========================================================================== */
71 /* Replace spaces w/another character so emacs core font parsing routines
74 ns_escape_name (char *name)
76 int i =0, len =strlen (name);
83 /* Reconstruct spaces in a font family name passed through emacs. */
85 ns_unescape_name (char *name)
87 int i =0, len =strlen (name);
94 /* Extract family name from a font spec. */
96 ns_get_family (Lisp_Object font_spec)
98 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
103 char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
105 ns_unescape_name (tmp);
106 family = [NSString stringWithUTF8String: tmp];
113 /* Return 0 if attr not set, else value (which might also be 0).
114 On Leopard 0 gets returned even on descriptors where the attribute
115 was never set, so there's no way to distinguish between unspecified
116 and set to not have. Callers should assume 0 means unspecified. */
118 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
120 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
121 NSNumber *val = [tdict objectForKey: trait];
122 return val == nil ? 0.0 : [val floatValue];
126 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
127 to NSFont descriptor. Information under extra only needed for matching. */
128 #define STYLE_REF 100
129 static NSFontDescriptor *
130 ns_spec_to_descriptor (Lisp_Object font_spec)
132 NSFontDescriptor *fdesc;
133 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
134 NSMutableDictionary *tdict = [NSMutableDictionary new];
135 NSString *family = ns_get_family (font_spec);
138 /* add each attr in font_spec to fdAttrs.. */
139 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
140 if (n != -1 && n != STYLE_REF)
141 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
142 forKey: NSFontWeightTrait];
143 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
144 if (n != -1 && n != STYLE_REF)
145 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
146 forKey: NSFontSlantTrait];
147 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
148 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
149 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
150 forKey: NSFontWidthTrait];
151 if ([tdict count] > 0)
152 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
154 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
157 fdesc = [fdesc fontDescriptorWithFamily: family];
166 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
168 ns_descriptor_to_entity (NSFontDescriptor *desc,
172 Lisp_Object font_entity = font_make_entity ();
173 /* NSString *psName = [desc postscriptName]; */
174 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
175 unsigned int traits = [desc symbolicTraits];
178 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
180 family = [desc objectForKey: NSFontNameAttribute];
182 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
184 escapedFamily = xstrdup ([family UTF8String]);
185 ns_escape_name (escapedFamily);
187 ASET (font_entity, FONT_TYPE_INDEX, Qns);
188 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
189 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
190 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
191 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
193 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
194 traits & NSFontBoldTrait ? Qbold : Qmedium);
195 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
196 make_number (100 + 100
197 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
198 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
199 traits & NSFontItalicTrait ? Qitalic : Qnormal);
200 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
201 make_number (100 + 100
202 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
203 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
204 traits & NSFontCondensedTrait ? Qcondensed :
205 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
206 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
207 make_number (100 + 100
208 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
210 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
211 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
212 ASET (font_entity, FONT_SPACING_INDEX,
213 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
214 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
216 ASET (font_entity, FONT_EXTRA_INDEX, extra);
217 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
221 fprintf (stderr, "created font_entity:\n ");
222 debug_print (font_entity);
225 xfree (escapedFamily);
230 /* Default font entity. */
232 ns_fallback_entity (void)
234 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
235 fontDescriptor], Qnil, NULL);
239 /* Utility: get width of a char c in screen font SFONT */
241 ns_char_width (NSFont *sfont, int c)
244 NSString *cstr = [NSString stringWithFormat: @"%c", c];
247 NSGlyph glyph = [sfont glyphWithName: cstr];
249 w = [sfont advancementForGlyph: glyph].width;
254 NSDictionary *attrsDictionary =
255 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
256 w = [cstr sizeWithAttributes: attrsDictionary].width;
262 /* Return average width over ASCII printable characters for SFONT. */
264 static NSString *ascii_printable;
267 ns_ascii_average_width (NSFont *sfont)
271 if (!ascii_printable)
275 for (ch = 0; ch < 95; ch++)
276 chars[ch] = ' ' + ch;
279 ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
283 NSGlyph glyph = [sfont glyphWithName: ascii_printable];
285 w = [sfont advancementForGlyph: glyph].width;
290 NSDictionary *attrsDictionary =
291 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
292 w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
295 return lrint (w / 95.0);
299 /* Return whether set1 covers set2 to a reasonable extent given by pct.
300 We check, out of each 16 Unicode char range containing chars in set2,
301 whether at least one character is present in set1.
302 This must be true for pct of the pairs to consider it covering. */
304 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
306 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
307 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
308 int i, off = 0, tot = 0;
310 /* Work around what appears to be a GNUstep bug.
311 See <http://bugs.gnu.org/11853>. */
312 if (! (bytes1 && bytes2))
315 for (i=0; i<4096; i++, bytes1++, bytes2++)
319 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
322 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
323 return (float)off / tot < 1.0 - pct;
327 /* Convert :lang property to a script. Use of :lang property by font backend
328 seems to be limited for now (2009/05) to ja, zh, and ko. */
330 *ns_lang_to_script (Lisp_Object lang)
332 if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
334 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
335 have more characters. */
336 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
338 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
345 /* Convert OTF 4-letter script code to emacs script name. (Why can't
346 everyone just use some standard Unicode names for these?) */
348 *ns_otf_to_script (Lisp_Object otf)
350 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
351 return CONSP (script)
352 ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
357 /* Convert a font registry, such as */
359 *ns_registry_to_script (char *reg)
361 Lisp_Object script, r, rts = Vns_reg_to_script;
364 r = XCAR (XCAR (rts));
365 if (!strncmp(SSDATA(r), reg, strlen(SSDATA(r))))
367 script = XCDR (XCAR (rts));
368 return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
376 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
377 plus registry regular property, for something that can be mapped to a
378 Unicode script. Empty string returned if no script spec found. */
380 *ns_get_req_script (Lisp_Object font_spec)
382 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
383 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
385 /* The extra-bundle properties have priority. */
386 for ( ; CONSP (extra); extra = XCDR (extra))
388 Lisp_Object tmp = XCAR (extra);
391 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
392 if (EQ (key, QCscript) && SYMBOLP (val))
393 return [NSString stringWithUTF8String:
394 SSDATA (SYMBOL_NAME (val))];
395 if (EQ (key, QClang) && SYMBOLP (val))
396 return ns_lang_to_script (val);
397 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
398 return ns_otf_to_script (val);
402 /* If we get here, check the charset portion of the registry. */
405 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
406 (which causes box rendering if we don't treat it like iso8858-1)
407 but also for ascii (which causes unnecessary font substitution). */
409 if (EQ (reg, Qiso10646_1))
412 return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
419 /* This small function is static in fontset.c. If it can be made public for
420 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
422 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
424 if (EQ (XCAR (arg), val))
427 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
429 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
434 /* Use the Unicode range information in Vchar_script_table to convert a script
435 name into an NSCharacterSet. */
436 static NSCharacterSet
437 *ns_script_to_charset (NSString *scriptName)
439 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
440 Lisp_Object script = intern ([scriptName UTF8String]);
441 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
443 if (! NILP (Fmemq (script, script_list)))
445 Lisp_Object ranges, range_list;
447 ranges = Fcons (script, Qnil);
448 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
450 range_list = Fnreverse (XCDR (ranges));
451 if (! NILP (range_list))
453 for (; CONSP (range_list); range_list = XCDR (range_list))
455 int start = XINT (XCAR (XCAR (range_list)));
456 int end = XINT (XCDR (XCAR (range_list)));
458 debug_print (XCAR (range_list));
460 [charset addCharactersInRange:
461 NSMakeRange (start, end-start)];
469 /* Return an array of font families containing characters for the given
470 script, for the given coverage criterion, including at least LastResort.
471 Results are cached by script for faster access.
472 If none are found, we reduce the percentage and try again, until 5%.
473 This provides a font with at least some characters if such can be found.
474 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
475 (b) need approximate match as fonts covering full Unicode ranges are rare. */
477 *ns_get_covering_families (NSString *script, float pct)
479 static NSMutableDictionary *scriptToFamilies = nil;
480 NSMutableSet *families;
483 NSLog(@"Request covering families for script: '%@'", script);
485 if (scriptToFamilies == nil)
486 scriptToFamilies = [[NSMutableDictionary alloc] init];
488 if ((families = [scriptToFamilies objectForKey: script]) == nil)
490 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
491 NSArray *allFamilies = [fontMgr availableFontFamilies];
493 if ([script length] == 0)
494 families = [NSMutableSet setWithArray: allFamilies];
497 NSCharacterSet *charset = ns_script_to_charset (script);
499 families = [NSMutableSet setWithCapacity: 10];
502 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
503 while ((family = [allFamiliesEnum nextObject]))
505 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
506 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
507 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
509 fset = [NSCharacterSet characterSetWithRange:
510 NSMakeRange (0, 127)];
511 if (ns_charset_covers(fset, charset, pct))
512 [families addObject: family];
515 if ([families count] > 0 || pct < 0.05)
521 if ([families count] == 0)
522 [families addObject: @"LastResort"];
524 [scriptToFamilies setObject: families forKey: script];
528 NSLog(@" returning %d families", [families count]);
533 /* Implementation for list() and match(). List() can return nil, match()
534 must return something. Strategy is to drop family name from attribute
535 matching set for match. */
537 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
539 Lisp_Object tem, list = Qnil;
540 NSFontDescriptor *fdesc, *desc;
542 NSArray *matchingDescs;
550 fprintf (stderr, "nsfont: %s for fontspec:\n ",
551 (isMatch ? "match" : "list"));
552 debug_print (font_spec);
555 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
557 fdesc = ns_spec_to_descriptor (font_spec);
558 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
560 [fkeys removeObject: NSFontFamilyAttribute];
562 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
564 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
565 [matchingDescs count]);
567 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
569 if (![cFamilies containsObject:
570 [desc objectForKey: NSFontFamilyAttribute]])
572 tem = ns_descriptor_to_entity (desc,
573 AREF (font_spec, FONT_EXTRA_INDEX),
577 list = Fcons (tem, list);
578 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
582 /* Add synthItal member if needed. */
583 family = [fdesc objectForKey: NSFontFamilyAttribute];
584 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
586 NSFontDescriptor *s1 = [NSFontDescriptor new];
587 NSFontDescriptor *sDesc
588 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
589 fontDescriptorWithFamily: family];
590 list = Fcons (ns_descriptor_to_entity (sDesc,
591 AREF (font_spec, FONT_EXTRA_INDEX),
596 /* Return something if was a match and nothing found. */
598 return ns_fallback_entity ();
601 fprintf (stderr, " Returning %"pI"d entities.\n",
602 XINT (Flength (list)));
609 /* ==========================================================================
611 Font driver implementation
613 ========================================================================== */
616 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
617 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
618 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
619 static Lisp_Object nsfont_list_family (Lisp_Object frame);
620 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
622 static void nsfont_close (FRAME_PTR f, struct font *font);
623 static int nsfont_has_char (Lisp_Object entity, int c);
624 static unsigned int nsfont_encode_char (struct font *font, int c);
625 static int nsfont_text_extents (struct font *font, unsigned int *code,
626 int nglyphs, struct font_metrics *metrics);
627 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
628 bool with_background);
630 struct font_driver nsfont_driver =
633 1, /* case sensitive */
638 NULL, /*free_entity */
641 NULL, /* prepare_face */
642 NULL, /* done_face */
647 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
648 anchor_point, otf_capability, otf_driver,
649 start_for_frame, end_for_frame, shape */
653 /* Return a cache of font-entities on FRAME. The cache must be a
654 cons whose cdr part is the actual cache area. */
656 nsfont_get_cache (FRAME_PTR frame)
658 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
659 return (dpyinfo->name_list_element);
663 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
664 **list** of font-entities. This and match () are sole APIs that allocate
665 font-entities. Properties to be considered (2009/05/19) are:
666 regular: foundry, family, adstyle, registry
667 extended: script, lang, otf
668 "Extended" properties are not part of the vector but get stored as
669 lisp properties under FONT_EXTRA_INDEX.
671 The returned entities should have type set (to 'ns), plus the following:
672 foundry, family, adstyle, registry,
673 weight, slant, width, size (0 if scalable),
674 dpi, spacing, avgwidth (0 if scalable) */
676 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
678 return ns_findfonts (font_spec, NO);
682 /* Return a font entity most closely matching with FONT_SPEC on
683 FRAME. The closeness is determined by the font backend, thus
684 `face-font-selection-order' is ignored here.
685 Properties to be considered are same as for list(). */
687 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
689 return ns_findfonts(font_spec, YES);
693 /* List available families. The value is a list of family names
696 nsfont_list_family (Lisp_Object frame)
698 Lisp_Object list = Qnil;
699 NSEnumerator *families =
700 [[[NSFontManager sharedFontManager] availableFontFamilies]
703 while ((family = [families nextObject]))
704 list = Fcons (intern ([family UTF8String]), list);
705 /* FIXME: escape the name? */
708 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
709 XINT (Flength (list)));
715 /* Open a font specified by FONT_ENTITY on frame F. If the font is
716 scalable, open it with PIXEL_SIZE. */
718 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
721 unsigned int traits = 0;
722 struct nsfont_info *font_info;
724 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
725 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
727 NSFont *nsfont, *sfont;
730 Lisp_Object font_object;
732 static NSMutableDictionary *fontCache = nil;
735 /* 2008/03/08: The same font may end up being requested for different
736 entities, due to small differences in numeric values or other issues,
737 or for different copies of the same entity. Therefore we cache to
738 avoid creating multiple struct font objects (with metrics cache, etc.)
739 for the same NSFont object. */
740 if (fontCache == nil)
741 fontCache = [[NSMutableDictionary alloc] init];
745 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
746 debug_print (font_entity);
751 /* try to get it out of frame params */
752 Lisp_Object tem = get_frame_param (f, Qfontsize);
753 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
756 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
757 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
759 family = ns_get_family (font_entity);
761 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
762 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
763 when setting family in ns_spec_to_descriptor(). */
764 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
765 traits |= NSBoldFontMask;
766 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
767 traits |= NSItalicFontMask;
769 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
770 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
771 nsfont = [fontMgr fontWithFamily: family
772 traits: traits weight: fixLeopardBug
774 /* if didn't find, try synthetic italic */
775 if (nsfont == nil && synthItal)
777 nsfont = [fontMgr fontWithFamily: family
778 traits: traits & ~NSItalicFontMask
779 weight: fixLeopardBug size: pixel_size];
782 /* LastResort not really a family */
783 if (nsfont == nil && [@"LastResort" isEqualToString: family])
784 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
789 message_with_string ("*** Warning: font in family '%s' not found",
790 build_string ([family UTF8String]), 1);
791 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
795 NSLog (@"%@\n", nsfont);
797 /* Check the cache */
798 cached = [fontCache objectForKey: nsfont];
799 if (cached != nil && !synthItal)
802 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
803 XHASH (font_object) = [cached unsignedLongLongValue];
808 font_object = font_make_object (VECSIZE (struct nsfont_info),
809 font_entity, pixel_size);
812 [fontCache setObject: [NSNumber
813 numberWithUnsignedLongLong:
814 (unsigned long long) XHASH (font_object)]
819 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
820 font = (struct font *) font_info;
822 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
824 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
825 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
830 sfont = [nsfont screenFont];
834 /* non-metric backend font struct fields */
835 font = (struct font *) font_info;
836 font->pixel_size = [sfont pointSize];
837 font->driver = &nsfont_driver;
838 font->encoding_charset = -1;
839 font->repertory_charset = -1;
840 font->default_ascent = 0;
841 font->vertical_centering = 0;
842 font->baseline_offset = 0;
843 font->relative_compose = 0;
844 font->font_encoder = NULL;
846 font->props[FONT_FORMAT_INDEX] = Qns;
847 font->props[FONT_FILE_INDEX] = Qnil;
850 const char *fontName = [[nsfont fontName] UTF8String];
852 /* The values specified by fonts are not always exact. For
853 * example, a 6x8 font could specify that the descender is
854 * -2.00000405... (represented by 0xc000000220000000). Without
855 * adjustment, the code below would round the descender to -3,
856 * resulting in a font that would be one pixel higher than
858 CGFloat adjusted_descender = [sfont descender] + 0.0001;
860 #ifdef NS_IMPL_GNUSTEP
861 font_info->nsfont = sfont;
863 font_info->nsfont = nsfont;
865 [font_info->nsfont retain];
867 /* set up ns_font (defined in nsgui.h) */
868 font_info->name = xstrdup (fontName);
869 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
871 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
873 /* Metrics etc.; some fonts return an unusually large max advance, so we
874 only use it for fonts that have wide characters. */
875 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
876 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
878 brect = [sfont boundingRectForFont];
880 font_info->underpos = [sfont underlinePosition];
881 font_info->underwidth = [sfont underlineThickness];
882 font_info->size = font->pixel_size;
885 font_info->max_bounds.ascent = lrint ([sfont ascender]);
886 /* Descender is usually negative. Use floor to avoid
887 clipping descenders. */
888 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
890 font_info->max_bounds.ascent + font_info->max_bounds.descent;
891 font_info->max_bounds.width = lrint (font_info->width);
892 font_info->max_bounds.lbearing = lrint (brect.origin.x);
893 font_info->max_bounds.rbearing =
894 lrint (brect.size.width - font_info->width);
897 /* set up synthItal and the CG font */
898 font_info->synthItal = synthItal;
900 ATSFontRef atsFont = ATSFontFindFromPostScriptName
901 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
903 if (atsFont == kATSFontRefUnspecified)
905 /* see if we can get it by dropping italic (then synthesizing) */
906 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
907 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
908 fontName], kATSOptionFlagsDefault);
909 if (atsFont != kATSFontRefUnspecified)
910 font_info->synthItal = YES;
913 /* last resort fallback */
914 atsFont = ATSFontFindFromPostScriptName
915 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
918 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
922 /* set up metrics portion of font struct */
923 font->ascent = lrint([sfont ascender]);
924 font->descent = -lrint(floor(adjusted_descender));
925 font->space_width = lrint (ns_char_width (sfont, ' '));
926 font->max_width = lrint (font_info->max_bounds.width);
927 font->min_width = font->space_width; /* Approximate. */
928 font->average_width = ns_ascii_average_width (sfont);
930 font->height = lrint (font_info->height);
931 font->underline_position = lrint (font_info->underpos);
932 font->underline_thickness = lrint (font_info->underwidth);
934 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
935 font->props[FONT_FULLNAME_INDEX] =
936 make_unibyte_string (font_info->name, strlen (font_info->name));
944 /* Close FONT on frame F. */
946 nsfont_close (FRAME_PTR f, struct font *font)
948 struct nsfont_info *font_info = (struct nsfont_info *)font;
951 /* FIXME: this occurs apparently due to same failure to detect same font
952 that causes need for cache in nsfont_open () */
956 for (i =0; i<0x100; i++)
958 xfree (font_info->glyphs[i]);
959 xfree (font_info->metrics[i]);
961 [font_info->nsfont release];
963 CGFontRelease (font_info->cgfont);
965 xfree (font_info->name);
970 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
971 return 1. If not, return 0. If a font must be opened to check
974 nsfont_has_char (Lisp_Object entity, int c)
980 /* Return a glyph code of FONT for character C (Unicode code point).
981 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
983 nsfont_encode_char (struct font *font, int c)
985 struct nsfont_info *font_info = (struct nsfont_info *)font;
986 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
990 return FONT_INVALID_CODE;
992 /* did we already cache this block? */
993 if (!font_info->glyphs[high])
994 ns_uni_to_glyphs (font_info, high);
996 g = font_info->glyphs[high][low];
997 return g == 0xFFFF ? FONT_INVALID_CODE : g;
1001 /* Perform the size computation of glyphs of FONT and fill in members
1002 of METRICS. The glyphs are specified by their glyph codes in
1003 CODE (length NGLYPHS). */
1005 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
1006 struct font_metrics *metrics)
1008 struct nsfont_info *font_info = (struct nsfont_info *)font;
1009 struct font_metrics *pcm;
1010 unsigned char high, low;
1014 memset (metrics, 0, sizeof (struct font_metrics));
1016 for (i =0; i<nglyphs; i++)
1018 /* get metrics for this glyph, filling cache if need be */
1019 /* TODO: get metrics for whole string from an NSLayoutManager
1020 (if not too slow) */
1021 high = (code[i] & 0xFF00) >> 8;
1022 low = code[i] & 0x00FF;
1023 if (!font_info->metrics[high])
1024 ns_glyph_metrics (font_info, high);
1025 pcm = &(font_info->metrics[high][low]);
1027 if (metrics->lbearing > totalWidth + pcm->lbearing)
1028 metrics->lbearing = totalWidth + pcm->lbearing;
1029 if (metrics->rbearing < totalWidth + pcm->rbearing)
1030 metrics->rbearing = totalWidth + pcm->rbearing;
1031 if (metrics->ascent < pcm->ascent)
1032 metrics->ascent = pcm->ascent;
1033 if (metrics->descent < pcm->descent)
1034 metrics->descent = pcm->descent;
1036 totalWidth += pcm->width;
1039 metrics->width = totalWidth;
1041 return totalWidth; /* not specified in doc, but xfont.c does it */
1045 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1046 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1047 fill the background in advance. It is assured that WITH_BACKGROUND
1048 is false when (FROM > 0 || TO < S->nchars). */
1050 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1051 bool with_background)
1052 /* NOTE: focus and clip must be set
1053 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1055 static char cbuf[1024];
1057 #ifdef NS_IMPL_GNUSTEP
1058 static float advances[1024];
1059 float *adv = advances;
1061 static CGSize advances[1024];
1062 CGSize *adv = advances;
1066 struct nsfont_info *font = ns_tmp_font;
1067 NSColor *col, *bgCol;
1068 unsigned short *t = s->char2b;
1070 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1071 int end = isComposite ? s->cmp_to : s->nchars;
1073 /* Select face based on input flags */
1074 switch (ns_tmp_flags)
1076 case NS_DUMPGLYPH_CURSOR:
1079 case NS_DUMPGLYPH_MOUSEFACE:
1080 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1082 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1089 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1090 r.origin.x += abs (s->face->box_line_width);
1093 r.size.height = FONT_HEIGHT (font);
1095 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1096 NS to render the string, it will come out differently from the individual
1097 character widths added up because of layout processing. */
1099 int cwidth, twidth = 0;
1101 /* FIXME: composition: no vertical displacement is considered. */
1102 t += s->cmp_from; /* advance into composition */
1103 for (i = s->cmp_from; i < end; i++, t++)
1105 hi = (*t & 0xFF00) >> 8;
1109 if (!s->first_glyph->u.cmp.automatic)
1110 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1113 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1114 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1115 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1116 cwidth = LGLYPH_WIDTH (glyph);
1119 cwidth = LGLYPH_WADJUST (glyph);
1120 #ifdef NS_IMPL_GNUSTEP
1121 *(adv-1) += LGLYPH_XOFF (glyph);
1123 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1130 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1131 ns_glyph_metrics (font, hi);
1132 cwidth = font->metrics[hi][lo].width;
1135 #ifdef NS_IMPL_GNUSTEP
1137 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1139 (*adv++).width = cwidth;
1142 len = adv - advances;
1143 r.size.width = twidth;
1147 /* fill background if requested */
1148 if (with_background && !isComposite)
1151 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1152 int mbox_line_width = max (s->face->box_line_width, 0);
1154 if (s->row->full_width_p)
1156 if (br.origin.x <= fibw + 1 + mbox_line_width)
1158 br.size.width += br.origin.x - mbox_line_width;
1159 br.origin.x = mbox_line_width;
1161 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1163 br.size.width += fibw;
1165 if (s->face->box == FACE_NO_BOX)
1167 /* expand unboxed top row over internal border */
1168 if (br.origin.y <= fibw + 1 + mbox_line_width)
1170 br.size.height += br.origin.y;
1176 int correction = abs (s->face->box_line_width)+1;
1177 br.origin.y += correction;
1178 br.size.height -= 2*correction;
1179 br.origin.x += correction;
1180 br.size.width -= 2*correction;
1183 if (!s->face->stipple)
1184 [(NS_FACE_BACKGROUND (face) != 0
1185 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1186 : FRAME_BACKGROUND_COLOR (s->f)) set];
1189 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1190 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1196 /* set up for character rendering */
1197 r.origin.y = s->ybase;
1199 col = (NS_FACE_FOREGROUND (face) != 0
1200 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1201 : FRAME_FOREGROUND_COLOR (s->f));
1202 /* FIXME: find another way to pass this */
1203 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1204 : (NS_FACE_BACKGROUND (face) != 0
1205 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1206 : FRAME_BACKGROUND_COLOR (s->f)));
1208 /* render under GNUstep using DPS */
1209 #ifdef NS_IMPL_GNUSTEP
1211 NSGraphicsContext *context = GSCurrentContext ();
1216 /* do erase if "foreground" mode */
1220 DPSmoveto (context, r.origin.x, r.origin.y);
1221 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1222 DPSxshow (context, cbuf, advances, len);
1223 DPSstroke (context);
1225 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1230 /* draw with DPSxshow () */
1231 DPSmoveto (context, r.origin.x, r.origin.y);
1232 DPSxshow (context, cbuf, advances, len);
1233 DPSstroke (context);
1235 DPSgrestore (context);
1238 #else /* NS_IMPL_COCOA */
1240 CGContextRef gcontext =
1241 [[NSGraphicsContext currentContext] graphicsPort];
1242 static CGAffineTransform fliptf;
1243 static BOOL firstTime = YES;
1248 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1251 CGContextSaveGState (gcontext);
1253 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1255 CGContextSetFont (gcontext, font->cgfont);
1256 CGContextSetFontSize (gcontext, font->size);
1257 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1258 CGContextSetShouldAntialias (gcontext, 0);
1260 CGContextSetShouldAntialias (gcontext, 1);
1262 CGContextSetTextMatrix (gcontext, fliptf);
1266 /* foreground drawing; erase first to avoid overstrike */
1268 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1269 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1270 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1271 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1276 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1277 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1280 if (face->overstrike)
1282 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1283 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1287 CGContextRestoreGState (gcontext);
1289 #endif /* NS_IMPL_COCOA */
1291 /* Draw underline, overline, strike-through. */
1292 ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1299 /* ==========================================================================
1301 Font glyph and metrics caching functions
1303 ========================================================================== */
1305 /* Find and cache corresponding glyph codes for unicode values in given
1306 hi-byte block of 256. */
1308 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1310 #ifdef NS_IMPL_COCOA
1311 static EmacsGlyphStorage *glyphStorage;
1312 static char firstTime = 1;
1314 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1315 unsigned int i, g, idx;
1316 unsigned short *glyphs;
1319 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1324 #ifdef NS_IMPL_COCOA
1328 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1332 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1333 if (!unichars || !(font_info->glyphs[block]))
1336 /* create a string containing all Unicode characters in this block */
1337 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1338 if (idx < 0xD800 || idx > 0xDFFF)
1341 unichars[i] = 0xFEFF;
1342 unichars[0x100] = 0;
1345 #ifdef NS_IMPL_COCOA
1346 NSString *allChars = [[NSString alloc]
1347 initWithCharactersNoCopy: unichars
1350 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1351 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1352 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1353 NSUInteger gInd = 0, cInd = 0;
1355 [glyphStorage setString: allChars font: font_info->nsfont];
1356 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1357 desiredNumberOfCharacters: glyphStorage->maxChar
1358 glyphIndex: &gInd characterIndex: &cInd];
1360 glyphs = font_info->glyphs[block];
1361 for (i = 0; i < 0x100; i++, glyphs++)
1363 #ifdef NS_IMPL_GNUSTEP
1366 g = glyphStorage->cglyphs[i];
1367 /* TODO: is this a good check? maybe need to use coveredChars.. */
1369 g = 0xFFFF; /* hopefully unused... */
1374 #ifdef NS_IMPL_COCOA
1384 /* Determine and cache metrics for corresponding glyph codes in given
1385 hi-byte block of 256. */
1387 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1390 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1392 struct font_metrics *metrics;
1395 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1398 #ifdef NS_IMPL_GNUSTEP
1399 /* not implemented yet (as of startup 0.18), so punt */
1401 numGlyphs = 0x10000;
1405 sfont = [font_info->nsfont screenFont];
1407 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1408 if (!(font_info->metrics[block]))
1411 metrics = font_info->metrics[block];
1412 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1415 NSRect r = [sfont boundingRectForGlyph: g];
1417 w = max ([sfont advancementForGlyph: g].width, 2.0);
1418 metrics->width = lrint (w);
1421 rb = r.size.width - w;
1423 metrics->lbearing = round (lb);
1424 if (font_info->ital)
1425 rb += 0.22 * font_info->height;
1426 metrics->rbearing = lrint (w + rb);
1428 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1429 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1430 metrics->ascent = r.size.height - metrics->descent;
1431 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1437 #ifdef NS_IMPL_COCOA
1438 /* helper for font glyph setup */
1439 @implementation EmacsGlyphStorage
1443 return [self initWithCapacity: 1024];
1446 - initWithCapacity: (unsigned long) c
1448 self = [super init];
1451 dict = [NSMutableDictionary new];
1452 cglyphs = xmalloc (c * sizeof (CGGlyph));
1465 - (void) setString: (NSString *)str font: (NSFont *)font
1467 [dict setObject: font forKey: NSFontAttributeName];
1470 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1471 maxChar = [str length];
1475 /* NSGlyphStorage protocol */
1476 - (NSUInteger)layoutOptions
1481 - (NSAttributedString *)attributedString
1486 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1487 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1488 characterIndex: (NSUInteger)charIndex
1490 len = glyphIndex+length;
1491 for (i =glyphIndex; i<len; i++)
1492 cglyphs[i] = glyphs[i-glyphIndex];
1497 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1498 forGlyphAtIndex: (NSUInteger)glyphIndex
1504 #endif /* NS_IMPL_COCOA */
1509 ns_dump_glyphstring (struct glyph_string *s)
1513 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1514 "overlap = %d, bg_filled = %d:",
1515 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1516 s->row->overlapping_p, s->background_filled_p);
1517 for (i =0; i<s->nchars; i++)
1518 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1519 fprintf (stderr, "\n");
1524 syms_of_nsfont (void)
1526 nsfont_driver.type = Qns;
1527 register_font_driver (&nsfont_driver, NULL);
1528 DEFSYM (Qapple, "apple");
1529 DEFSYM (Qroman, "roman");
1530 DEFSYM (Qmedium, "medium");
1531 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1532 doc: /* Internal use: maps font registry to Unicode script. */);
1534 ascii_printable = NULL;