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 if ([fkeys count] > 0)
563 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
565 matchingDescs = [NSMutableArray array];
568 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
569 [matchingDescs count]);
571 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
573 if (![cFamilies containsObject:
574 [desc objectForKey: NSFontFamilyAttribute]])
576 tem = ns_descriptor_to_entity (desc,
577 AREF (font_spec, FONT_EXTRA_INDEX),
581 list = Fcons (tem, list);
582 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
586 /* Add synthItal member if needed. */
587 family = [fdesc objectForKey: NSFontFamilyAttribute];
588 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
590 NSFontDescriptor *s1 = [NSFontDescriptor new];
591 NSFontDescriptor *sDesc
592 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
593 fontDescriptorWithFamily: family];
594 list = Fcons (ns_descriptor_to_entity (sDesc,
595 AREF (font_spec, FONT_EXTRA_INDEX),
600 /* Return something if was a match and nothing found. */
602 return ns_fallback_entity ();
605 fprintf (stderr, " Returning %"pI"d entities.\n",
606 XINT (Flength (list)));
613 /* ==========================================================================
615 Font driver implementation
617 ========================================================================== */
620 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
621 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
622 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
623 static Lisp_Object nsfont_list_family (Lisp_Object frame);
624 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
626 static void nsfont_close (FRAME_PTR f, struct font *font);
627 static int nsfont_has_char (Lisp_Object entity, int c);
628 static unsigned int nsfont_encode_char (struct font *font, int c);
629 static int nsfont_text_extents (struct font *font, unsigned int *code,
630 int nglyphs, struct font_metrics *metrics);
631 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
632 bool with_background);
634 struct font_driver nsfont_driver =
637 1, /* case sensitive */
642 NULL, /*free_entity */
645 NULL, /* prepare_face */
646 NULL, /* done_face */
651 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
652 anchor_point, otf_capability, otf_driver,
653 start_for_frame, end_for_frame, shape */
657 /* Return a cache of font-entities on FRAME. The cache must be a
658 cons whose cdr part is the actual cache area. */
660 nsfont_get_cache (FRAME_PTR frame)
662 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
663 return (dpyinfo->name_list_element);
667 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
668 **list** of font-entities. This and match () are sole APIs that allocate
669 font-entities. Properties to be considered (2009/05/19) are:
670 regular: foundry, family, adstyle, registry
671 extended: script, lang, otf
672 "Extended" properties are not part of the vector but get stored as
673 lisp properties under FONT_EXTRA_INDEX.
675 The returned entities should have type set (to 'ns), plus the following:
676 foundry, family, adstyle, registry,
677 weight, slant, width, size (0 if scalable),
678 dpi, spacing, avgwidth (0 if scalable) */
680 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
682 return ns_findfonts (font_spec, NO);
686 /* Return a font entity most closely matching with FONT_SPEC on
687 FRAME. The closeness is determined by the font backend, thus
688 `face-font-selection-order' is ignored here.
689 Properties to be considered are same as for list(). */
691 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
693 return ns_findfonts(font_spec, YES);
697 /* List available families. The value is a list of family names
700 nsfont_list_family (Lisp_Object frame)
702 Lisp_Object list = Qnil;
703 NSEnumerator *families =
704 [[[NSFontManager sharedFontManager] availableFontFamilies]
707 while ((family = [families nextObject]))
708 list = Fcons (intern ([family UTF8String]), list);
709 /* FIXME: escape the name? */
712 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
713 XINT (Flength (list)));
719 /* Open a font specified by FONT_ENTITY on frame F. If the font is
720 scalable, open it with PIXEL_SIZE. */
722 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
725 unsigned int traits = 0;
726 struct nsfont_info *font_info;
728 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
729 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
731 NSFont *nsfont, *sfont;
734 Lisp_Object font_object;
739 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
740 debug_print (font_entity);
745 /* try to get it out of frame params */
746 Lisp_Object tem = get_frame_param (f, Qfontsize);
747 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
750 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
751 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
753 family = ns_get_family (font_entity);
755 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
756 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
757 when setting family in ns_spec_to_descriptor(). */
758 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
759 traits |= NSBoldFontMask;
760 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
761 traits |= NSItalicFontMask;
763 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
764 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
765 nsfont = [fontMgr fontWithFamily: family
766 traits: traits weight: fixLeopardBug
768 /* if didn't find, try synthetic italic */
769 if (nsfont == nil && synthItal)
771 nsfont = [fontMgr fontWithFamily: family
772 traits: traits & ~NSItalicFontMask
773 weight: fixLeopardBug size: pixel_size];
776 /* LastResort not really a family */
777 if (nsfont == nil && [@"LastResort" isEqualToString: family])
778 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
783 message_with_string ("*** Warning: font in family '%s' not found",
784 build_string ([family UTF8String]), 1);
785 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
789 NSLog (@"%@\n", nsfont);
791 font_object = font_make_object (VECSIZE (struct nsfont_info),
792 font_entity, pixel_size);
793 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
794 font = (struct font *) font_info;
796 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
798 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
799 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
805 sfont = [nsfont screenFontWithRenderingMode:
806 NSFontAntialiasedIntegerAdvancementsRenderingMode];
808 sfont = [nsfont screenFont];
814 /* non-metric backend font struct fields */
815 font = (struct font *) font_info;
816 font->pixel_size = [sfont pointSize];
817 font->driver = &nsfont_driver;
818 font->encoding_charset = -1;
819 font->repertory_charset = -1;
820 font->default_ascent = 0;
821 font->vertical_centering = 0;
822 font->baseline_offset = 0;
823 font->relative_compose = 0;
824 font->font_encoder = NULL;
826 font->props[FONT_FORMAT_INDEX] = Qns;
827 font->props[FONT_FILE_INDEX] = Qnil;
830 const char *fontName = [[nsfont fontName] UTF8String];
832 /* The values specified by fonts are not always exact. For
833 * example, a 6x8 font could specify that the descender is
834 * -2.00000405... (represented by 0xc000000220000000). Without
835 * adjustment, the code below would round the descender to -3,
836 * resulting in a font that would be one pixel higher than
838 CGFloat adjusted_descender = [sfont descender] + 0.0001;
840 #ifdef NS_IMPL_GNUSTEP
841 font_info->nsfont = sfont;
843 font_info->nsfont = nsfont;
845 [font_info->nsfont retain];
847 /* set up ns_font (defined in nsgui.h) */
848 font_info->name = xstrdup (fontName);
849 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
851 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
853 /* Metrics etc.; some fonts return an unusually large max advance, so we
854 only use it for fonts that have wide characters. */
855 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
856 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
858 brect = [sfont boundingRectForFont];
860 font_info->underpos = [sfont underlinePosition];
861 font_info->underwidth = [sfont underlineThickness];
862 font_info->size = font->pixel_size;
865 font_info->max_bounds.ascent = lrint ([sfont ascender]);
866 /* Descender is usually negative. Use floor to avoid
867 clipping descenders. */
868 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
870 font_info->max_bounds.ascent + font_info->max_bounds.descent;
871 font_info->max_bounds.width = lrint (font_info->width);
872 font_info->max_bounds.lbearing = lrint (brect.origin.x);
873 font_info->max_bounds.rbearing =
874 lrint (brect.size.width - font_info->width);
877 /* set up synthItal and the CG font */
878 font_info->synthItal = synthItal;
880 ATSFontRef atsFont = ATSFontFindFromPostScriptName
881 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
883 if (atsFont == kATSFontRefUnspecified)
885 /* see if we can get it by dropping italic (then synthesizing) */
886 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
887 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
888 fontName], kATSOptionFlagsDefault);
889 if (atsFont != kATSFontRefUnspecified)
890 font_info->synthItal = YES;
893 /* last resort fallback */
894 atsFont = ATSFontFindFromPostScriptName
895 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
898 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
902 /* set up metrics portion of font struct */
903 font->ascent = lrint([sfont ascender]);
904 font->descent = -lrint(floor(adjusted_descender));
905 font->space_width = lrint (ns_char_width (sfont, ' '));
906 font->max_width = lrint (font_info->max_bounds.width);
907 font->min_width = font->space_width; /* Approximate. */
908 font->average_width = ns_ascii_average_width (sfont);
910 font->height = lrint (font_info->height);
911 font->underline_position = lrint (font_info->underpos);
912 font->underline_thickness = lrint (font_info->underwidth);
914 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
915 font->props[FONT_FULLNAME_INDEX] =
916 make_unibyte_string (font_info->name, strlen (font_info->name));
924 /* Close FONT on frame F. */
926 nsfont_close (FRAME_PTR f, struct font *font)
928 struct nsfont_info *font_info = (struct nsfont_info *)font;
931 /* FIXME: this occurs apparently due to same failure to detect same font
932 that causes need for cache in nsfont_open () */
936 for (i =0; i<0x100; i++)
938 xfree (font_info->glyphs[i]);
939 xfree (font_info->metrics[i]);
941 [font_info->nsfont release];
943 CGFontRelease (font_info->cgfont);
945 xfree (font_info->name);
950 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
951 return 1. If not, return 0. If a font must be opened to check
954 nsfont_has_char (Lisp_Object entity, int c)
960 /* Return a glyph code of FONT for character C (Unicode code point).
961 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
963 nsfont_encode_char (struct font *font, int c)
965 struct nsfont_info *font_info = (struct nsfont_info *)font;
966 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
970 return FONT_INVALID_CODE;
972 /* did we already cache this block? */
973 if (!font_info->glyphs[high])
974 ns_uni_to_glyphs (font_info, high);
976 g = font_info->glyphs[high][low];
977 return g == 0xFFFF ? FONT_INVALID_CODE : g;
981 /* Perform the size computation of glyphs of FONT and fill in members
982 of METRICS. The glyphs are specified by their glyph codes in
983 CODE (length NGLYPHS). */
985 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
986 struct font_metrics *metrics)
988 struct nsfont_info *font_info = (struct nsfont_info *)font;
989 struct font_metrics *pcm;
990 unsigned char high, low;
994 memset (metrics, 0, sizeof (struct font_metrics));
996 for (i =0; i<nglyphs; i++)
998 /* get metrics for this glyph, filling cache if need be */
999 /* TODO: get metrics for whole string from an NSLayoutManager
1000 (if not too slow) */
1001 high = (code[i] & 0xFF00) >> 8;
1002 low = code[i] & 0x00FF;
1003 if (!font_info->metrics[high])
1004 ns_glyph_metrics (font_info, high);
1005 pcm = &(font_info->metrics[high][low]);
1007 if (metrics->lbearing > totalWidth + pcm->lbearing)
1008 metrics->lbearing = totalWidth + pcm->lbearing;
1009 if (metrics->rbearing < totalWidth + pcm->rbearing)
1010 metrics->rbearing = totalWidth + pcm->rbearing;
1011 if (metrics->ascent < pcm->ascent)
1012 metrics->ascent = pcm->ascent;
1013 if (metrics->descent < pcm->descent)
1014 metrics->descent = pcm->descent;
1016 totalWidth += pcm->width;
1019 metrics->width = totalWidth;
1021 return totalWidth; /* not specified in doc, but xfont.c does it */
1025 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1026 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1027 fill the background in advance. It is assured that WITH_BACKGROUND
1028 is false when (FROM > 0 || TO < S->nchars). */
1030 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1031 bool with_background)
1032 /* NOTE: focus and clip must be set
1033 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1035 static char cbuf[1024];
1037 #ifdef NS_IMPL_GNUSTEP
1038 static float advances[1024];
1039 float *adv = advances;
1041 static CGSize advances[1024];
1042 CGSize *adv = advances;
1046 struct nsfont_info *font = ns_tmp_font;
1047 NSColor *col, *bgCol;
1048 unsigned short *t = s->char2b;
1050 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1051 int end = isComposite ? s->cmp_to : s->nchars;
1053 /* Select face based on input flags */
1054 switch (ns_tmp_flags)
1056 case NS_DUMPGLYPH_CURSOR:
1059 case NS_DUMPGLYPH_MOUSEFACE:
1060 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1062 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1069 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1070 r.origin.x += abs (s->face->box_line_width);
1073 r.size.height = FONT_HEIGHT (font);
1075 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1076 NS to render the string, it will come out differently from the individual
1077 character widths added up because of layout processing. */
1079 int cwidth, twidth = 0;
1081 /* FIXME: composition: no vertical displacement is considered. */
1082 t += s->cmp_from; /* advance into composition */
1083 for (i = s->cmp_from; i < end; i++, t++)
1085 hi = (*t & 0xFF00) >> 8;
1089 if (!s->first_glyph->u.cmp.automatic)
1090 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1093 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1094 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1095 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1096 cwidth = LGLYPH_WIDTH (glyph);
1099 cwidth = LGLYPH_WADJUST (glyph);
1100 #ifdef NS_IMPL_GNUSTEP
1101 *(adv-1) += LGLYPH_XOFF (glyph);
1103 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1110 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1111 ns_glyph_metrics (font, hi);
1112 cwidth = font->metrics[hi][lo].width;
1115 #ifdef NS_IMPL_GNUSTEP
1117 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1119 (*adv++).width = cwidth;
1122 len = adv - advances;
1123 r.size.width = twidth;
1127 /* fill background if requested */
1128 if (with_background && !isComposite)
1131 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1132 int mbox_line_width = max (s->face->box_line_width, 0);
1134 if (s->row->full_width_p)
1136 if (br.origin.x <= fibw + 1 + mbox_line_width)
1138 br.size.width += br.origin.x - mbox_line_width;
1139 br.origin.x = mbox_line_width;
1141 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1143 br.size.width += fibw;
1145 if (s->face->box == FACE_NO_BOX)
1147 /* expand unboxed top row over internal border */
1148 if (br.origin.y <= fibw + 1 + mbox_line_width)
1150 br.size.height += br.origin.y;
1156 int correction = abs (s->face->box_line_width)+1;
1157 br.origin.y += correction;
1158 br.size.height -= 2*correction;
1159 br.origin.x += correction;
1160 br.size.width -= 2*correction;
1163 if (!s->face->stipple)
1164 [(NS_FACE_BACKGROUND (face) != 0
1165 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1166 : FRAME_BACKGROUND_COLOR (s->f)) set];
1169 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1170 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1176 /* set up for character rendering */
1177 r.origin.y = s->ybase;
1179 col = (NS_FACE_FOREGROUND (face) != 0
1180 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1181 : FRAME_FOREGROUND_COLOR (s->f));
1182 /* FIXME: find another way to pass this */
1183 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1184 : (NS_FACE_BACKGROUND (face) != 0
1185 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1186 : FRAME_BACKGROUND_COLOR (s->f)));
1188 /* render under GNUstep using DPS */
1189 #ifdef NS_IMPL_GNUSTEP
1191 NSGraphicsContext *context = GSCurrentContext ();
1196 /* do erase if "foreground" mode */
1200 DPSmoveto (context, r.origin.x, r.origin.y);
1201 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1202 DPSxshow (context, cbuf, advances, len);
1203 DPSstroke (context);
1205 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1210 /* draw with DPSxshow () */
1211 DPSmoveto (context, r.origin.x, r.origin.y);
1212 DPSxshow (context, cbuf, advances, len);
1213 DPSstroke (context);
1215 DPSgrestore (context);
1218 #else /* NS_IMPL_COCOA */
1220 CGContextRef gcontext =
1221 [[NSGraphicsContext currentContext] graphicsPort];
1222 static CGAffineTransform fliptf;
1223 static BOOL firstTime = YES;
1228 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1231 CGContextSaveGState (gcontext);
1233 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1235 CGContextSetFont (gcontext, font->cgfont);
1236 CGContextSetFontSize (gcontext, font->size);
1237 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1238 CGContextSetShouldAntialias (gcontext, 0);
1240 CGContextSetShouldAntialias (gcontext, 1);
1242 CGContextSetShouldSmoothFonts (gcontext, NO);
1243 CGContextSetTextMatrix (gcontext, fliptf);
1247 /* foreground drawing; erase first to avoid overstrike */
1249 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1250 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1251 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1252 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1257 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1258 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1261 if (face->overstrike)
1263 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1264 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1268 CGContextRestoreGState (gcontext);
1270 #endif /* NS_IMPL_COCOA */
1272 /* Draw underline, overline, strike-through. */
1273 ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1280 /* ==========================================================================
1282 Font glyph and metrics caching functions
1284 ========================================================================== */
1286 /* Find and cache corresponding glyph codes for unicode values in given
1287 hi-byte block of 256. */
1289 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1291 #ifdef NS_IMPL_COCOA
1292 static EmacsGlyphStorage *glyphStorage;
1293 static char firstTime = 1;
1295 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1296 unsigned int i, g, idx;
1297 unsigned short *glyphs;
1300 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1305 #ifdef NS_IMPL_COCOA
1309 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1313 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1314 if (!unichars || !(font_info->glyphs[block]))
1317 /* create a string containing all Unicode characters in this block */
1318 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1319 if (idx < 0xD800 || idx > 0xDFFF)
1322 unichars[i] = 0xFEFF;
1323 unichars[0x100] = 0;
1326 #ifdef NS_IMPL_COCOA
1327 NSString *allChars = [[NSString alloc]
1328 initWithCharactersNoCopy: unichars
1331 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1332 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1333 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1334 NSUInteger gInd = 0, cInd = 0;
1336 [glyphStorage setString: allChars font: font_info->nsfont];
1337 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1338 desiredNumberOfCharacters: glyphStorage->maxChar
1339 glyphIndex: &gInd characterIndex: &cInd];
1341 glyphs = font_info->glyphs[block];
1342 for (i = 0; i < 0x100; i++, glyphs++)
1344 #ifdef NS_IMPL_GNUSTEP
1347 g = glyphStorage->cglyphs[i];
1348 /* TODO: is this a good check? maybe need to use coveredChars.. */
1350 g = 0xFFFF; /* hopefully unused... */
1355 #ifdef NS_IMPL_COCOA
1365 /* Determine and cache metrics for corresponding glyph codes in given
1366 hi-byte block of 256. */
1368 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1371 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1373 struct font_metrics *metrics;
1376 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1379 #ifdef NS_IMPL_GNUSTEP
1380 /* not implemented yet (as of startup 0.18), so punt */
1382 numGlyphs = 0x10000;
1386 #ifdef NS_IMPL_COCOA
1387 sfont = [font_info->nsfont screenFontWithRenderingMode:
1388 NSFontAntialiasedIntegerAdvancementsRenderingMode];
1390 sfont = [font_info->nsfont screenFont];
1393 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1394 if (!(font_info->metrics[block]))
1397 metrics = font_info->metrics[block];
1398 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1401 NSRect r = [sfont boundingRectForGlyph: g];
1403 w = max ([sfont advancementForGlyph: g].width, 2.0);
1404 metrics->width = lrint (w);
1407 rb = r.size.width - w;
1409 metrics->lbearing = round (lb);
1410 if (font_info->ital)
1411 rb += 0.22 * font_info->height;
1412 metrics->rbearing = lrint (w + rb);
1414 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1415 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1416 metrics->ascent = r.size.height - metrics->descent;
1417 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1423 #ifdef NS_IMPL_COCOA
1424 /* helper for font glyph setup */
1425 @implementation EmacsGlyphStorage
1429 return [self initWithCapacity: 1024];
1432 - initWithCapacity: (unsigned long) c
1434 self = [super init];
1437 dict = [NSMutableDictionary new];
1438 cglyphs = xmalloc (c * sizeof (CGGlyph));
1451 - (void) setString: (NSString *)str font: (NSFont *)font
1453 [dict setObject: font forKey: NSFontAttributeName];
1456 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1457 maxChar = [str length];
1461 /* NSGlyphStorage protocol */
1462 - (NSUInteger)layoutOptions
1467 - (NSAttributedString *)attributedString
1472 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1473 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1474 characterIndex: (NSUInteger)charIndex
1476 len = glyphIndex+length;
1477 for (i =glyphIndex; i<len; i++)
1478 cglyphs[i] = glyphs[i-glyphIndex];
1483 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1484 forGlyphAtIndex: (NSUInteger)glyphIndex
1490 #endif /* NS_IMPL_COCOA */
1495 ns_dump_glyphstring (struct glyph_string *s)
1499 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1500 "overlap = %d, bg_filled = %d:",
1501 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1502 s->row->overlapping_p, s->background_filled_p);
1503 for (i =0; i<s->nchars; i++)
1504 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1505 fprintf (stderr, "\n");
1510 syms_of_nsfont (void)
1512 nsfont_driver.type = Qns;
1513 register_font_driver (&nsfont_driver, NULL);
1514 DEFSYM (Qapple, "apple");
1515 DEFSYM (Qroman, "roman");
1516 DEFSYM (Qmedium, "medium");
1517 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1518 doc: /* Internal use: maps font registry to Unicode script. */);
1520 ascii_printable = NULL;