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. */
29 #include "dispextern.h"
30 #include "composite.h"
31 #include "blockinput.h"
38 #include "character.h"
42 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
43 #ifdef NS_IMPL_GNUSTEP
44 #import <AppKit/NSFontDescriptor.h>
47 #define NSFONT_TRACE 0
49 extern Lisp_Object Qns;
50 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
51 static Lisp_Object Qapple, Qroman, Qmedium;
52 extern Lisp_Object Qappend;
53 extern float ns_antialias_threshold;
54 extern int ns_tmp_flags;
55 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;
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 int 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_type = FONT_ENCODING_NOT_DECIDED;
836 font->encoding_charset = -1;
837 font->repertory_charset = -1;
838 font->default_ascent = 0;
839 font->vertical_centering = 0;
840 font->baseline_offset = 0;
841 font->relative_compose = 0;
842 font->font_encoder = NULL;
844 font->props[FONT_FORMAT_INDEX] = Qns;
845 font->props[FONT_FILE_INDEX] = Qnil;
848 const char *fontName = [[nsfont fontName] UTF8String];
850 /* The values specified by fonts are not always exact. For
851 * example, a 6x8 font could specify that the descender is
852 * -2.00000405... (represented by 0xc000000220000000). Without
853 * adjustment, the code below would round the descender to -3,
854 * resulting in a font that would be one pixel higher than
856 CGFloat adjusted_descender = [sfont descender] + 0.0001;
858 #ifdef NS_IMPL_GNUSTEP
859 font_info->nsfont = sfont;
861 font_info->nsfont = nsfont;
863 [font_info->nsfont retain];
865 /* set up ns_font (defined in nsgui.h) */
866 font_info->name = xstrdup (fontName);
867 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
869 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
871 /* Metrics etc.; some fonts return an unusually large max advance, so we
872 only use it for fonts that have wide characters. */
873 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
874 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
876 brect = [sfont boundingRectForFont];
878 font_info->underpos = [sfont underlinePosition];
879 font_info->underwidth = [sfont underlineThickness];
880 font_info->size = font->pixel_size;
883 font_info->max_bounds.ascent = lrint ([sfont ascender]);
884 /* Descender is usually negative. Use floor to avoid
885 clipping descenders. */
886 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
888 font_info->max_bounds.ascent + font_info->max_bounds.descent;
889 font_info->max_bounds.width = lrint (font_info->width);
890 font_info->max_bounds.lbearing = lrint (brect.origin.x);
891 font_info->max_bounds.rbearing =
892 lrint (brect.size.width - font_info->width);
895 /* set up synthItal and the CG font */
896 font_info->synthItal = synthItal;
898 ATSFontRef atsFont = ATSFontFindFromPostScriptName
899 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
901 if (atsFont == kATSFontRefUnspecified)
903 /* see if we can get it by dropping italic (then synthesizing) */
904 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
905 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
906 fontName], kATSOptionFlagsDefault);
907 if (atsFont != kATSFontRefUnspecified)
908 font_info->synthItal = YES;
911 /* last resort fallback */
912 atsFont = ATSFontFindFromPostScriptName
913 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
916 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
920 /* set up metrics portion of font struct */
921 font->ascent = lrint([sfont ascender]);
922 font->descent = -lrint(floor(adjusted_descender));
923 font->space_width = lrint (ns_char_width (sfont, ' '));
924 font->max_width = lrint (font_info->max_bounds.width);
925 font->min_width = font->space_width; /* Approximate. */
926 font->average_width = ns_ascii_average_width (sfont);
928 font->height = lrint (font_info->height);
929 font->underline_position = lrint (font_info->underpos);
930 font->underline_thickness = lrint (font_info->underwidth);
932 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
933 font->props[FONT_FULLNAME_INDEX] =
934 make_unibyte_string (font_info->name, strlen (font_info->name));
942 /* Close FONT on frame F. */
944 nsfont_close (FRAME_PTR f, struct font *font)
946 struct nsfont_info *font_info = (struct nsfont_info *)font;
949 /* FIXME: this occurs apparently due to same failure to detect same font
950 that causes need for cache in nsfont_open () */
954 for (i =0; i<0x100; i++)
956 xfree (font_info->glyphs[i]);
957 xfree (font_info->metrics[i]);
959 [font_info->nsfont release];
961 CGFontRelease (font_info->cgfont);
963 xfree (font_info->name);
968 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
969 return 1. If not, return 0. If a font must be opened to check
972 nsfont_has_char (Lisp_Object entity, int c)
978 /* Return a glyph code of FONT for character C (Unicode code point).
979 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
981 nsfont_encode_char (struct font *font, int c)
983 struct nsfont_info *font_info = (struct nsfont_info *)font;
984 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
988 return FONT_INVALID_CODE;
990 /* did we already cache this block? */
991 if (!font_info->glyphs[high])
992 ns_uni_to_glyphs (font_info, high);
994 g = font_info->glyphs[high][low];
995 return g == 0xFFFF ? FONT_INVALID_CODE : g;
999 /* Perform the size computation of glyphs of FONT and fill in members
1000 of METRICS. The glyphs are specified by their glyph codes in
1001 CODE (length NGLYPHS). */
1003 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
1004 struct font_metrics *metrics)
1006 struct nsfont_info *font_info = (struct nsfont_info *)font;
1007 struct font_metrics *pcm;
1008 unsigned char high, low;
1012 memset (metrics, 0, sizeof (struct font_metrics));
1014 for (i =0; i<nglyphs; i++)
1016 /* get metrics for this glyph, filling cache if need be */
1017 /* TODO: get metrics for whole string from an NSLayoutManager
1018 (if not too slow) */
1019 high = (code[i] & 0xFF00) >> 8;
1020 low = code[i] & 0x00FF;
1021 if (!font_info->metrics[high])
1022 ns_glyph_metrics (font_info, high);
1023 pcm = &(font_info->metrics[high][low]);
1025 if (metrics->lbearing > totalWidth + pcm->lbearing)
1026 metrics->lbearing = totalWidth + pcm->lbearing;
1027 if (metrics->rbearing < totalWidth + pcm->rbearing)
1028 metrics->rbearing = totalWidth + pcm->rbearing;
1029 if (metrics->ascent < pcm->ascent)
1030 metrics->ascent = pcm->ascent;
1031 if (metrics->descent < pcm->descent)
1032 metrics->descent = pcm->descent;
1034 totalWidth += pcm->width;
1037 metrics->width = totalWidth;
1039 return totalWidth; /* not specified in doc, but xfont.c does it */
1043 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1044 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
1045 is nonzero, fill the background in advance. It is assured that
1046 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1048 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1049 int with_background)
1050 /* NOTE: focus and clip must be set
1051 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1053 static char cbuf[1024];
1055 #ifdef NS_IMPL_GNUSTEP
1056 static float advances[1024];
1057 float *adv = advances;
1059 static CGSize advances[1024];
1060 CGSize *adv = advances;
1064 struct nsfont_info *font = ns_tmp_font;
1065 NSColor *col, *bgCol;
1066 unsigned short *t = s->char2b;
1068 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1069 int end = isComposite ? s->cmp_to : s->nchars;
1071 /* Select face based on input flags */
1072 switch (ns_tmp_flags)
1074 case NS_DUMPGLYPH_CURSOR:
1077 case NS_DUMPGLYPH_MOUSEFACE:
1078 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1080 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1087 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1088 r.origin.x += abs (s->face->box_line_width);
1091 r.size.height = FONT_HEIGHT (font);
1093 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1094 NS to render the string, it will come out differently from the individual
1095 character widths added up because of layout processing. */
1097 int cwidth, twidth = 0;
1099 /* FIXME: composition: no vertical displacement is considered. */
1100 t += s->cmp_from; /* advance into composition */
1101 for (i = s->cmp_from; i < end; i++, t++)
1103 hi = (*t & 0xFF00) >> 8;
1107 if (!s->first_glyph->u.cmp.automatic)
1108 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1111 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1112 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1113 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1114 cwidth = LGLYPH_WIDTH (glyph);
1117 cwidth = LGLYPH_WADJUST (glyph);
1118 #ifdef NS_IMPL_GNUSTEP
1119 *(adv-1) += LGLYPH_XOFF (glyph);
1121 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1128 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1129 ns_glyph_metrics (font, hi);
1130 cwidth = font->metrics[hi][lo].width;
1133 #ifdef NS_IMPL_GNUSTEP
1135 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1137 (*adv++).width = cwidth;
1140 len = adv - advances;
1141 r.size.width = twidth;
1145 /* fill background if requested */
1146 if (with_background && !isComposite)
1149 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1150 int mbox_line_width = max (s->face->box_line_width, 0);
1152 if (s->row->full_width_p)
1154 if (br.origin.x <= fibw + 1 + mbox_line_width)
1156 br.size.width += br.origin.x - mbox_line_width;
1157 br.origin.x = mbox_line_width;
1159 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1161 br.size.width += fibw;
1163 if (s->face->box == FACE_NO_BOX)
1165 /* expand unboxed top row over internal border */
1166 if (br.origin.y <= fibw + 1 + mbox_line_width)
1168 br.size.height += br.origin.y;
1174 int correction = abs (s->face->box_line_width)+1;
1175 br.origin.y += correction;
1176 br.size.height -= 2*correction;
1177 br.origin.x += correction;
1178 br.size.width -= 2*correction;
1181 if (!s->face->stipple)
1182 [(NS_FACE_BACKGROUND (face) != 0
1183 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1184 : FRAME_BACKGROUND_COLOR (s->f)) set];
1187 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1188 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1194 /* set up for character rendering */
1195 r.origin.y = s->ybase;
1197 col = (NS_FACE_FOREGROUND (face) != 0
1198 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1199 : FRAME_FOREGROUND_COLOR (s->f));
1200 /* FIXME: find another way to pass this */
1201 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1202 : (NS_FACE_BACKGROUND (face) != 0
1203 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1204 : FRAME_BACKGROUND_COLOR (s->f)));
1206 /* render under GNUstep using DPS */
1207 #ifdef NS_IMPL_GNUSTEP
1209 NSGraphicsContext *context = GSCurrentContext ();
1214 /* do erase if "foreground" mode */
1218 DPSmoveto (context, r.origin.x, r.origin.y);
1219 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1220 DPSxshow (context, cbuf, advances, len);
1221 DPSstroke (context);
1223 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1228 /* draw with DPSxshow () */
1229 DPSmoveto (context, r.origin.x, r.origin.y);
1230 DPSxshow (context, cbuf, advances, len);
1231 DPSstroke (context);
1233 DPSgrestore (context);
1236 #else /* NS_IMPL_COCOA */
1238 CGContextRef gcontext =
1239 [[NSGraphicsContext currentContext] graphicsPort];
1240 static CGAffineTransform fliptf;
1241 static BOOL firstTime = YES;
1246 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1249 CGContextSaveGState (gcontext);
1251 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1253 CGContextSetFont (gcontext, font->cgfont);
1254 CGContextSetFontSize (gcontext, font->size);
1255 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1256 CGContextSetShouldAntialias (gcontext, 0);
1258 CGContextSetShouldAntialias (gcontext, 1);
1260 CGContextSetTextMatrix (gcontext, fliptf);
1264 /* foreground drawing; erase first to avoid overstrike */
1266 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1267 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1268 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1269 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1274 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1275 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1278 if (face->overstrike)
1280 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1281 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1285 CGContextRestoreGState (gcontext);
1287 #endif /* NS_IMPL_COCOA */
1289 /* Draw underline, overline, strike-through. */
1290 ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1297 /* ==========================================================================
1299 Font glyph and metrics caching functions
1301 ========================================================================== */
1303 /* Find and cache corresponding glyph codes for unicode values in given
1304 hi-byte block of 256. */
1306 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1308 #ifdef NS_IMPL_COCOA
1309 static EmacsGlyphStorage *glyphStorage;
1310 static char firstTime = 1;
1312 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1313 unsigned int i, g, idx;
1314 unsigned short *glyphs;
1317 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1322 #ifdef NS_IMPL_COCOA
1326 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1330 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1331 if (!unichars || !(font_info->glyphs[block]))
1334 /* create a string containing all Unicode characters in this block */
1335 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1336 if (idx < 0xD800 || idx > 0xDFFF)
1339 unichars[i] = 0xFEFF;
1340 unichars[0x100] = 0;
1343 #ifdef NS_IMPL_COCOA
1344 NSString *allChars = [[NSString alloc]
1345 initWithCharactersNoCopy: unichars
1348 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1349 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1350 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1351 NSUInteger gInd = 0, cInd = 0;
1353 [glyphStorage setString: allChars font: font_info->nsfont];
1354 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1355 desiredNumberOfCharacters: glyphStorage->maxChar
1356 glyphIndex: &gInd characterIndex: &cInd];
1358 glyphs = font_info->glyphs[block];
1359 for (i = 0; i < 0x100; i++, glyphs++)
1361 #ifdef NS_IMPL_GNUSTEP
1364 g = glyphStorage->cglyphs[i];
1365 /* TODO: is this a good check? maybe need to use coveredChars.. */
1367 g = 0xFFFF; /* hopefully unused... */
1372 #ifdef NS_IMPL_COCOA
1382 /* Determine and cache metrics for corresponding glyph codes in given
1383 hi-byte block of 256. */
1385 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1388 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1390 struct font_metrics *metrics;
1393 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1396 #ifdef NS_IMPL_GNUSTEP
1397 /* not implemented yet (as of startup 0.18), so punt */
1399 numGlyphs = 0x10000;
1403 sfont = [font_info->nsfont screenFont];
1405 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1406 if (!(font_info->metrics[block]))
1409 metrics = font_info->metrics[block];
1410 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1413 NSRect r = [sfont boundingRectForGlyph: g];
1415 w = max ([sfont advancementForGlyph: g].width, 2.0);
1416 metrics->width = lrint (w);
1419 rb = r.size.width - w;
1421 metrics->lbearing = round (lb);
1422 if (font_info->ital)
1423 rb += 0.22 * font_info->height;
1424 metrics->rbearing = lrint (w + rb);
1426 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1427 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1428 metrics->ascent = r.size.height - metrics->descent;
1429 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1435 #ifdef NS_IMPL_COCOA
1436 /* helper for font glyph setup */
1437 @implementation EmacsGlyphStorage
1441 return [self initWithCapacity: 1024];
1444 - initWithCapacity: (unsigned long) c
1446 self = [super init];
1449 dict = [NSMutableDictionary new];
1450 cglyphs = xmalloc (c * sizeof (CGGlyph));
1463 - (void) setString: (NSString *)str font: (NSFont *)font
1465 [dict setObject: font forKey: NSFontAttributeName];
1468 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1469 maxChar = [str length];
1473 /* NSGlyphStorage protocol */
1474 - (NSUInteger)layoutOptions
1479 - (NSAttributedString *)attributedString
1484 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1485 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1486 characterIndex: (NSUInteger)charIndex
1488 len = glyphIndex+length;
1489 for (i =glyphIndex; i<len; i++)
1490 cglyphs[i] = glyphs[i-glyphIndex];
1495 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1496 forGlyphAtIndex: (NSUInteger)glyphIndex
1502 #endif /* NS_IMPL_COCOA */
1507 ns_dump_glyphstring (struct glyph_string *s)
1511 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1512 "overlap = %d, bg_filled = %d:",
1513 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1514 s->row->overlapping_p, s->background_filled_p);
1515 for (i =0; i<s->nchars; i++)
1516 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1517 fprintf (stderr, "\n");
1522 syms_of_nsfont (void)
1524 nsfont_driver.type = Qns;
1525 register_font_driver (&nsfont_driver, NULL);
1526 DEFSYM (Qapple, "apple");
1527 DEFSYM (Qroman, "roman");
1528 DEFSYM (Qmedium, "medium");
1529 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1530 doc: /* Internal use: maps font registry to Unicode script. */);
1532 ascii_printable = NULL;