1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006-2014 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"
36 #include "character.h"
40 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
41 #ifdef NS_IMPL_GNUSTEP
42 #import <AppKit/NSFontDescriptor.h>
45 #define NSFONT_TRACE 0
46 #define LCD_SMOOTHING_MARGIN 2
48 extern Lisp_Object Qns;
49 extern Lisp_Object Qnormal, Qbold, Qitalic;
50 static Lisp_Object Qapple, Qroman, Qmedium;
51 static Lisp_Object Qcondensed, Qexpanded;
52 extern Lisp_Object Qappend;
53 extern float ns_antialias_threshold;
56 /* font glyph and metrics caching functions, implemented at end */
57 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
59 static void ns_glyph_metrics (struct nsfont_info *font_info,
62 #define INVALID_GLYPH 0xFFFF
64 /* ==========================================================================
68 ========================================================================== */
71 /* Replace spaces w/another character so emacs core font parsing routines
74 ns_escape_name (char *name)
82 /* Reconstruct spaces in a font family name passed through emacs. */
84 ns_unescape_name (char *name)
92 /* Extract family name from a font spec. */
94 ns_get_family (Lisp_Object font_spec)
96 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
101 char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
103 ns_unescape_name (tmp);
104 family = [NSString stringWithUTF8String: tmp];
111 /* Return 0 if attr not set, else value (which might also be 0).
112 On Leopard 0 gets returned even on descriptors where the attribute
113 was never set, so there's no way to distinguish between unspecified
114 and set to not have. Callers should assume 0 means unspecified. */
116 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
118 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
119 NSNumber *val = [tdict objectForKey: trait];
120 return val == nil ? 0.0F : [val floatValue];
124 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
125 to NSFont descriptor. Information under extra only needed for matching. */
126 #define STYLE_REF 100
127 static NSFontDescriptor *
128 ns_spec_to_descriptor (Lisp_Object font_spec)
130 NSFontDescriptor *fdesc;
131 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
132 NSMutableDictionary *tdict = [NSMutableDictionary new];
133 NSString *family = ns_get_family (font_spec);
136 /* add each attr in font_spec to fdAttrs.. */
137 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
138 if (n != -1 && n != STYLE_REF)
139 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
140 forKey: NSFontWeightTrait];
141 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
142 if (n != -1 && n != STYLE_REF)
143 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
144 forKey: NSFontSlantTrait];
145 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
146 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
147 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
148 forKey: NSFontWidthTrait];
149 if ([tdict count] > 0)
150 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
152 fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
153 retain] autorelease];
157 NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
158 fdesc = [[fdesc2 retain] autorelease];
167 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
169 ns_descriptor_to_entity (NSFontDescriptor *desc,
173 Lisp_Object font_entity = font_make_entity ();
174 /* NSString *psName = [desc postscriptName]; */
175 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
176 unsigned int traits = [desc symbolicTraits];
179 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
181 family = [desc objectForKey: NSFontNameAttribute];
183 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
185 escapedFamily = xstrdup ([family UTF8String]);
186 ns_escape_name (escapedFamily);
188 ASET (font_entity, FONT_TYPE_INDEX, Qns);
189 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
190 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
191 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
192 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
194 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
195 traits & NSFontBoldTrait ? Qbold : Qmedium);
196 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
197 make_number (100 + 100
198 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
199 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
200 traits & NSFontItalicTrait ? Qitalic : Qnormal);
201 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
202 make_number (100 + 100
203 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
204 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
205 traits & NSFontCondensedTrait ? Qcondensed :
206 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
207 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
208 make_number (100 + 100
209 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
211 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
212 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
213 ASET (font_entity, FONT_SPACING_INDEX,
214 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
215 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
217 ASET (font_entity, FONT_EXTRA_INDEX, extra);
218 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
222 fprintf (stderr, "created font_entity:\n ");
223 debug_print (font_entity);
226 xfree (escapedFamily);
231 /* Default font entity. */
233 ns_fallback_entity (void)
235 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
236 fontDescriptor], Qnil, NULL);
240 /* Utility: get width of a char c in screen font SFONT */
242 ns_char_width (NSFont *sfont, int c)
245 NSString *cstr = [NSString stringWithFormat: @"%c", c];
248 NSGlyph glyph = [sfont glyphWithName: cstr];
250 w = [sfont advancementForGlyph: glyph].width;
255 NSDictionary *attrsDictionary =
256 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
257 w = [cstr sizeWithAttributes: attrsDictionary].width;
263 /* Return average width over ASCII printable characters for SFONT. */
265 static NSString *ascii_printable;
268 ns_ascii_average_width (NSFont *sfont)
272 if (!ascii_printable)
276 for (ch = 0; ch < 95; ch++)
277 chars[ch] = ' ' + ch;
280 ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
284 NSGlyph glyph = [sfont glyphWithName: ascii_printable];
286 w = [sfont advancementForGlyph: glyph].width;
289 if (w < (CGFloat) 0.0)
291 NSDictionary *attrsDictionary =
292 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
293 w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
296 return lrint (w / (CGFloat) 95.0);
300 /* Return whether set1 covers set2 to a reasonable extent given by pct.
301 We check, out of each 16 Unicode char range containing chars in set2,
302 whether at least one character is present in set1.
303 This must be true for pct of the pairs to consider it covering. */
305 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
307 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
308 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
309 int i, off = 0, tot = 0;
311 /* Work around what appears to be a GNUstep bug.
312 See <http://bugs.gnu.org/11853>. */
313 if (! (bytes1 && bytes2))
316 for (i=0; i<4096; i++, bytes1++, bytes2++)
320 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
323 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
324 return (float)off / tot < 1.0F - pct;
328 /* Convert :lang property to a script. Use of :lang property by font backend
329 seems to be limited for now (2009/05) to ja, zh, and ko. */
331 *ns_lang_to_script (Lisp_Object lang)
333 if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
335 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
336 have more characters. */
337 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
339 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
346 /* Convert OTF 4-letter script code to emacs script name. (Why can't
347 everyone just use some standard Unicode names for these?) */
349 *ns_otf_to_script (Lisp_Object otf)
351 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
352 return CONSP (script)
353 ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
358 /* Convert a font registry, such as */
360 *ns_registry_to_script (char *reg)
362 Lisp_Object script, r, rts = Vns_reg_to_script;
365 r = XCAR (XCAR (rts));
366 if (!strncmp (SSDATA (r), reg, SBYTES (r)))
368 script = XCDR (XCAR (rts));
369 return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
377 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
378 plus registry regular property, for something that can be mapped to a
379 Unicode script. Empty string returned if no script spec found. */
381 *ns_get_req_script (Lisp_Object font_spec)
383 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
384 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
386 /* The extra-bundle properties have priority. */
387 for ( ; CONSP (extra); extra = XCDR (extra))
389 Lisp_Object tmp = XCAR (extra);
392 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
393 if (EQ (key, QCscript) && SYMBOLP (val))
394 return [NSString stringWithUTF8String:
395 SSDATA (SYMBOL_NAME (val))];
396 if (EQ (key, QClang) && SYMBOLP (val))
397 return ns_lang_to_script (val);
398 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
399 return ns_otf_to_script (val);
403 /* If we get here, check the charset portion of the registry. */
406 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
407 (which causes box rendering if we don't treat it like iso8858-1)
408 but also for ascii (which causes unnecessary font substitution). */
410 if (EQ (reg, Qiso10646_1))
413 return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
420 /* This small function is static in fontset.c. If it can be made public for
421 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
423 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
425 if (EQ (XCAR (arg), val))
428 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
430 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
435 /* Use the Unicode range information in Vchar_script_table to convert a script
436 name into an NSCharacterSet. */
437 static NSCharacterSet
438 *ns_script_to_charset (NSString *scriptName)
440 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
441 Lisp_Object script = intern ([scriptName UTF8String]);
442 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
444 if (! NILP (Fmemq (script, script_list)))
446 Lisp_Object ranges, range_list;
448 ranges = list1 (script);
449 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
451 range_list = Fnreverse (XCDR (ranges));
452 if (! NILP (range_list))
454 for (; CONSP (range_list); range_list = XCDR (range_list))
456 int start = XINT (XCAR (XCAR (range_list)));
457 int end = XINT (XCDR (XCAR (range_list)));
459 debug_print (XCAR (range_list));
461 [charset addCharactersInRange:
462 NSMakeRange (start, end-start)];
470 /* Return an array of font families containing characters for the given
471 script, for the given coverage criterion, including at least LastResort.
472 Results are cached by script for faster access.
473 If none are found, we reduce the percentage and try again, until 5%.
474 This provides a font with at least some characters if such can be found.
475 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
476 (b) need approximate match as fonts covering full Unicode ranges are rare. */
478 *ns_get_covering_families (NSString *script, float pct)
480 static NSMutableDictionary *scriptToFamilies = nil;
481 NSMutableSet *families;
484 NSLog(@"Request covering families for script: '%@'", script);
486 if (scriptToFamilies == nil)
487 scriptToFamilies = [[NSMutableDictionary alloc] init];
489 if ((families = [scriptToFamilies objectForKey: script]) == nil)
491 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
492 NSArray *allFamilies = [fontMgr availableFontFamilies];
494 if ([script length] == 0)
495 families = [NSMutableSet setWithArray: allFamilies];
498 NSCharacterSet *charset = ns_script_to_charset (script);
500 families = [NSMutableSet setWithCapacity: 10];
503 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
504 while ((family = [allFamiliesEnum nextObject]))
506 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
507 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
508 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
510 fset = [NSCharacterSet characterSetWithRange:
511 NSMakeRange (0, 127)];
512 if (ns_charset_covers(fset, charset, pct))
513 [families addObject: family];
516 if ([families count] > 0 || pct < 0.05F)
522 if ([families count] == 0)
523 [families addObject: @"LastResort"];
525 [scriptToFamilies setObject: families forKey: script];
529 NSLog(@" returning %lu families", (unsigned long)[families count]);
534 /* Implementation for list() and match(). List() can return nil, match()
535 must return something. Strategy is to drop family name from attribute
536 matching set for match. */
538 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
540 Lisp_Object tem, list = Qnil;
541 NSFontDescriptor *fdesc, *desc;
543 NSArray *matchingDescs;
552 fprintf (stderr, "nsfont: %s for fontspec:\n ",
553 (isMatch ? "match" : "list"));
554 debug_print (font_spec);
557 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
559 fdesc = ns_spec_to_descriptor (font_spec);
560 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
562 [fkeys removeObject: NSFontFamilyAttribute];
564 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
567 NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
568 (unsigned long)[matchingDescs count]);
570 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
572 if (![cFamilies containsObject:
573 [desc objectForKey: NSFontFamilyAttribute]])
575 tem = ns_descriptor_to_entity (desc,
576 AREF (font_spec, FONT_EXTRA_INDEX),
580 list = Fcons (tem, list);
581 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
585 /* Add synthItal member if needed. */
586 family = [fdesc objectForKey: NSFontFamilyAttribute];
587 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
589 NSFontDescriptor *s1 = [NSFontDescriptor new];
590 NSFontDescriptor *sDesc
591 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
592 fontDescriptorWithFamily: family];
593 list = Fcons (ns_descriptor_to_entity (sDesc,
594 AREF (font_spec, FONT_EXTRA_INDEX),
601 /* Return something if was a match and nothing found. */
603 return ns_fallback_entity ();
606 fprintf (stderr, " Returning %"pI"d entities.\n",
607 XINT (Flength (list)));
614 /* ==========================================================================
616 Font driver implementation
618 ========================================================================== */
621 static Lisp_Object nsfont_get_cache (struct frame *frame);
622 static Lisp_Object nsfont_list (struct frame *, Lisp_Object);
623 static Lisp_Object nsfont_match (struct frame *, Lisp_Object);
624 static Lisp_Object nsfont_list_family (struct frame *);
625 static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity,
627 static void nsfont_close (struct font *font);
628 static int nsfont_has_char (Lisp_Object entity, int c);
629 static unsigned int nsfont_encode_char (struct font *font, int c);
630 static int nsfont_text_extents (struct font *font, unsigned int *code,
631 int nglyphs, struct font_metrics *metrics);
632 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
633 bool with_background);
635 struct font_driver nsfont_driver =
638 1, /* case sensitive */
643 NULL, /*free_entity */
646 NULL, /* prepare_face */
647 NULL, /* done_face */
652 /* excluded: get_bitmap, free_bitmap,
653 anchor_point, otf_capability, otf_driver,
654 start_for_frame, end_for_frame, shape */
658 /* Return a cache of font-entities on FRAME. The cache must be a
659 cons whose cdr part is the actual cache area. */
661 nsfont_get_cache (struct frame *frame)
663 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (frame);
664 return (dpyinfo->name_list_element);
668 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
669 **list** of font-entities. This and match () are sole APIs that allocate
670 font-entities. Properties to be considered (2009/05/19) are:
671 regular: foundry, family, adstyle, registry
672 extended: script, lang, otf
673 "Extended" properties are not part of the vector but get stored as
674 lisp properties under FONT_EXTRA_INDEX.
676 The returned entities should have type set (to 'ns), plus the following:
677 foundry, family, adstyle, registry,
678 weight, slant, width, size (0 if scalable),
679 dpi, spacing, avgwidth (0 if scalable) */
681 nsfont_list (struct frame *f, Lisp_Object font_spec)
683 return ns_findfonts (font_spec, NO);
687 /* Return a font entity most closely matching with FONT_SPEC on
688 FRAME. The closeness is determined by the font backend, thus
689 `face-font-selection-order' is ignored here.
690 Properties to be considered are same as for list(). */
692 nsfont_match (struct frame *f, Lisp_Object font_spec)
694 return ns_findfonts (font_spec, YES);
698 /* List available families. The value is a list of family names
701 nsfont_list_family (struct frame *f)
703 Lisp_Object list = Qnil;
704 NSEnumerator *families;
708 families = [[[NSFontManager sharedFontManager] availableFontFamilies]
710 while ((family = [families nextObject]))
711 list = Fcons (intern ([family UTF8String]), list);
712 /* FIXME: escape the name? */
715 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
716 XINT (Flength (list)));
723 /* Open a font specified by FONT_ENTITY on frame F. If the font is
724 scalable, open it with PIXEL_SIZE. */
726 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
729 unsigned int traits = 0;
730 struct nsfont_info *font_info;
732 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
733 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
735 NSFont *nsfont, *sfont;
738 Lisp_Object font_object;
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.50F)
765 traits |= NSBoldFontMask;
766 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
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 font_object = font_make_object (VECSIZE (struct nsfont_info),
798 font_entity, pixel_size);
799 ASET (font_object, FONT_TYPE_INDEX, nsfont_driver.type);
800 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
801 font = (struct font *) font_info;
805 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
808 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
809 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
813 sfont = [nsfont screenFontWithRenderingMode:
814 NSFontAntialiasedIntegerAdvancementsRenderingMode];
816 sfont = [nsfont screenFont];
822 /* non-metric backend font struct fields */
823 font = (struct font *) font_info;
824 font->pixel_size = [sfont pointSize];
825 font->driver = &nsfont_driver;
826 font->encoding_charset = -1;
827 font->repertory_charset = -1;
828 font->default_ascent = 0;
829 font->vertical_centering = 0;
830 font->baseline_offset = 0;
831 font->relative_compose = 0;
834 const char *fontName = [[nsfont fontName] UTF8String];
836 /* The values specified by fonts are not always exact. For
837 * example, a 6x8 font could specify that the descender is
838 * -2.00000405... (represented by 0xc000000220000000). Without
839 * adjustment, the code below would round the descender to -3,
840 * resulting in a font that would be one pixel higher than
842 CGFloat adjusted_descender = [sfont descender] + 0.0001;
844 #ifdef NS_IMPL_GNUSTEP
845 font_info->nsfont = sfont;
847 font_info->nsfont = nsfont;
849 [font_info->nsfont retain];
851 /* set up ns_font (defined in nsgui.h) */
852 font_info->name = xstrdup (fontName);
853 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
855 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
857 /* Metrics etc.; some fonts return an unusually large max advance, so we
858 only use it for fonts that have wide characters. */
859 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
860 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
862 brect = [sfont boundingRectForFont];
864 font_info->underpos = [sfont underlinePosition];
865 font_info->underwidth = [sfont underlineThickness];
866 font_info->size = font->pixel_size;
869 font->ascent = font_info->max_bounds.ascent = lrint ([sfont ascender]);
870 /* Descender is usually negative. Use floor to avoid
871 clipping descenders. */
873 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
875 font_info->max_bounds.ascent + font_info->max_bounds.descent;
876 font_info->max_bounds.width = lrint (font_info->width);
877 font_info->max_bounds.lbearing = lrint (brect.origin.x);
878 font_info->max_bounds.rbearing =
879 lrint (brect.size.width - (CGFloat) font_info->width);
882 /* set up synthItal and the CG font */
883 font_info->synthItal = synthItal;
885 ATSFontRef atsFont = ATSFontFindFromPostScriptName
886 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
888 if (atsFont == kATSFontRefUnspecified)
890 /* see if we can get it by dropping italic (then synthesizing) */
891 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
892 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
893 fontName], kATSOptionFlagsDefault);
894 if (atsFont != kATSFontRefUnspecified)
895 font_info->synthItal = YES;
898 /* last resort fallback */
899 atsFont = ATSFontFindFromPostScriptName
900 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
903 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
907 /* set up metrics portion of font struct */
908 font->ascent = lrint([sfont ascender]);
909 font->descent = -lrint(floor(adjusted_descender));
910 font->space_width = lrint (ns_char_width (sfont, ' '));
911 font->max_width = lrint (font_info->max_bounds.width);
912 font->min_width = font->space_width; /* Approximate. */
913 font->average_width = ns_ascii_average_width (sfont);
915 font->height = lrint (font_info->height);
916 font->underline_position = lrint (font_info->underpos);
917 font->underline_thickness = lrint (font_info->underwidth);
919 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
920 font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
930 nsfont_close (struct font *font)
932 struct nsfont_info *font_info = (struct nsfont_info *) font;
934 /* FIXME: font_info may be NULL due to same failure to detect
935 same font that causes need for cache in nsfont_open. */
936 if (font_info && font_info->name)
940 for (i = 0; i < 0x100; i++)
942 xfree (font_info->glyphs[i]);
943 xfree (font_info->metrics[i]);
945 xfree (font_info->glyphs);
946 xfree (font_info->metrics);
947 [font_info->nsfont release];
949 CGFontRelease (font_info->cgfont);
951 xfree (font_info->name);
952 font_info->name = NULL;
957 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
958 return 1. If not, return 0. If a font must be opened to check
961 nsfont_has_char (Lisp_Object entity, int c)
967 /* Return a glyph code of FONT for character C (Unicode code point).
968 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
970 nsfont_encode_char (struct font *font, int c)
972 struct nsfont_info *font_info = (struct nsfont_info *)font;
973 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
977 return FONT_INVALID_CODE;
979 /* did we already cache this block? */
980 if (!font_info->glyphs[high])
981 ns_uni_to_glyphs (font_info, high);
983 g = font_info->glyphs[high][low];
984 return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
988 /* Perform the size computation of glyphs of FONT and fill in members
989 of METRICS. The glyphs are specified by their glyph codes in
990 CODE (length NGLYPHS). */
992 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
993 struct font_metrics *metrics)
995 struct nsfont_info *font_info = (struct nsfont_info *)font;
996 struct font_metrics *pcm;
997 unsigned char high, low;
1001 memset (metrics, 0, sizeof (struct font_metrics));
1003 for (i =0; i<nglyphs; i++)
1005 /* get metrics for this glyph, filling cache if need be */
1006 /* TODO: get metrics for whole string from an NSLayoutManager
1007 (if not too slow) */
1008 high = (code[i] & 0xFF00) >> 8;
1009 low = code[i] & 0x00FF;
1010 if (!font_info->metrics[high])
1011 ns_glyph_metrics (font_info, high);
1012 pcm = &(font_info->metrics[high][low]);
1014 if (metrics->lbearing > totalWidth + pcm->lbearing)
1015 metrics->lbearing = totalWidth + pcm->lbearing;
1016 if (metrics->rbearing < totalWidth + pcm->rbearing)
1017 metrics->rbearing = totalWidth + pcm->rbearing;
1018 if (metrics->ascent < pcm->ascent)
1019 metrics->ascent = pcm->ascent;
1020 if (metrics->descent < pcm->descent)
1021 metrics->descent = pcm->descent;
1023 totalWidth += pcm->width;
1026 metrics->width = totalWidth;
1028 return totalWidth; /* not specified in doc, but xfont.c does it */
1032 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1033 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1034 fill the background in advance. It is assured that WITH_BACKGROUND
1035 is false when (FROM > 0 || TO < S->nchars). */
1037 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1038 bool with_background)
1039 /* NOTE: focus and clip must be set */
1041 static unsigned char cbuf[1024];
1042 unsigned char *c = cbuf;
1043 #ifdef NS_IMPL_GNUSTEP
1044 static float advances[1024];
1045 float *adv = advances;
1047 static CGSize advances[1024];
1048 CGSize *adv = advances;
1052 struct nsfont_info *font;
1053 NSColor *col, *bgCol;
1054 unsigned short *t = s->char2b;
1056 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1060 font = (struct nsfont_info *)s->face->font;
1062 font = (struct nsfont_info *)FRAME_FONT (s->f);
1064 /* Select face based on input flags */
1065 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
1066 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
1067 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
1068 NS_DUMPGLYPH_NORMAL));
1072 case NS_DUMPGLYPH_CURSOR:
1075 case NS_DUMPGLYPH_MOUSEFACE:
1076 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1078 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1085 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1086 r.origin.x += abs (s->face->box_line_width);
1089 r.size.height = FONT_HEIGHT (font);
1091 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1092 NS to render the string, it will come out differently from the individual
1093 character widths added up because of layout processing. */
1095 int cwidth, twidth = 0;
1097 /* FIXME: composition: no vertical displacement is considered. */
1098 t += from; /* advance into composition */
1099 for (i = from; i < to; i++, t++)
1101 hi = (*t & 0xFF00) >> 8;
1105 if (!s->first_glyph->u.cmp.automatic)
1106 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1109 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1110 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1111 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1112 cwidth = LGLYPH_WIDTH (glyph);
1115 cwidth = LGLYPH_WADJUST (glyph);
1116 #ifdef NS_IMPL_GNUSTEP
1117 *(adv-1) += LGLYPH_XOFF (glyph);
1119 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1126 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1127 ns_glyph_metrics (font, hi);
1128 cwidth = font->metrics[hi][lo].width;
1131 #ifdef NS_IMPL_GNUSTEP
1133 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1135 (*adv++).width = cwidth;
1138 len = adv - advances;
1139 r.size.width = twidth;
1143 /* fill background if requested */
1144 if (with_background && !isComposite)
1147 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1148 int mbox_line_width = max (s->face->box_line_width, 0);
1150 if (s->row->full_width_p)
1152 if (br.origin.x <= fibw + 1 + mbox_line_width)
1154 br.size.width += br.origin.x - mbox_line_width;
1155 br.origin.x = mbox_line_width;
1157 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1159 br.size.width += fibw;
1161 if (s->face->box == FACE_NO_BOX)
1163 /* expand unboxed top row over internal border */
1164 if (br.origin.y <= fibw + 1 + mbox_line_width)
1166 br.size.height += br.origin.y;
1172 int correction = abs (s->face->box_line_width)+1;
1173 br.origin.y += correction;
1174 br.size.height -= 2*correction;
1175 br.origin.x += correction;
1176 br.size.width -= 2*correction;
1179 if (!s->face->stipple)
1180 [(NS_FACE_BACKGROUND (face) != 0
1181 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1182 : FRAME_BACKGROUND_COLOR (s->f)) set];
1185 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
1186 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1192 /* set up for character rendering */
1195 col = (NS_FACE_FOREGROUND (face) != 0
1196 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1197 : FRAME_FOREGROUND_COLOR (s->f));
1199 bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
1200 : (NS_FACE_BACKGROUND (face) != 0
1201 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1202 : FRAME_BACKGROUND_COLOR (s->f)));
1204 /* render under GNUstep using DPS */
1205 #ifdef NS_IMPL_GNUSTEP
1207 NSGraphicsContext *context = GSCurrentContext ();
1212 /* do erase if "foreground" mode */
1216 DPSmoveto (context, r.origin.x, r.origin.y);
1217 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1218 DPSxshow (context, (const char *) cbuf, advances, len);
1219 DPSstroke (context);
1221 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1226 /* draw with DPSxshow () */
1227 DPSmoveto (context, r.origin.x, r.origin.y);
1228 DPSxshow (context, (const char *) cbuf, advances, len);
1229 DPSstroke (context);
1231 DPSgrestore (context);
1234 #else /* NS_IMPL_COCOA */
1236 CGContextRef gcontext =
1237 [[NSGraphicsContext currentContext] graphicsPort];
1238 static CGAffineTransform fliptf;
1239 static BOOL firstTime = YES;
1244 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1247 CGContextSaveGState (gcontext);
1249 // Used to be Fix2X (kATSItalicQDSkew), but Fix2X is deprecated
1250 // and kATSItalicQDSkew is 0.25.
1251 fliptf.c = font->synthItal ? 0.25 : 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 + from,
1278 if (face->overstrike)
1280 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1281 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1285 CGContextRestoreGState (gcontext);
1287 #endif /* NS_IMPL_COCOA */
1295 /* ==========================================================================
1297 Font glyph and metrics caching functions
1299 ========================================================================== */
1301 /* Find and cache corresponding glyph codes for unicode values in given
1302 hi-byte block of 256. */
1304 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1306 #ifdef NS_IMPL_COCOA
1307 static EmacsGlyphStorage *glyphStorage;
1308 static char firstTime = 1;
1310 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1311 unsigned int i, g, idx;
1312 unsigned short *glyphs;
1315 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1320 #ifdef NS_IMPL_COCOA
1324 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1328 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1329 if (!unichars || !(font_info->glyphs[block]))
1332 /* create a string containing all Unicode characters in this block */
1333 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1334 if (idx < 0xD800 || idx > 0xDFFF)
1337 unichars[i] = 0xFEFF;
1338 unichars[0x100] = 0;
1341 #ifdef NS_IMPL_COCOA
1342 NSString *allChars = [[NSString alloc]
1343 initWithCharactersNoCopy: unichars
1346 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1347 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1348 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1349 NSUInteger gInd = 0, cInd = 0;
1351 [glyphStorage setString: allChars font: font_info->nsfont];
1352 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1353 desiredNumberOfCharacters: glyphStorage->maxChar
1354 glyphIndex: &gInd characterIndex: &cInd];
1356 glyphs = font_info->glyphs[block];
1357 for (i = 0; i < 0x100; i++, glyphs++)
1359 #ifdef NS_IMPL_GNUSTEP
1362 g = glyphStorage->cglyphs[i];
1363 /* TODO: is this a good check? maybe need to use coveredChars.. */
1364 if (g > numGlyphs || g == NSNullGlyph)
1365 g = INVALID_GLYPH; /* hopefully unused... */
1370 #ifdef NS_IMPL_COCOA
1380 /* Determine and cache metrics for corresponding glyph codes in given
1381 hi-byte block of 256. */
1383 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1386 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1388 struct font_metrics *metrics;
1391 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1394 #ifdef NS_IMPL_GNUSTEP
1395 /* not implemented yet (as of startup 0.18), so punt */
1397 numGlyphs = 0x10000;
1401 #ifdef NS_IMPL_COCOA
1402 sfont = [font_info->nsfont screenFontWithRenderingMode:
1403 NSFontAntialiasedIntegerAdvancementsRenderingMode];
1405 sfont = [font_info->nsfont screenFont];
1408 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1409 if (!(font_info->metrics[block]))
1412 metrics = font_info->metrics[block];
1413 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1416 NSRect r = [sfont boundingRectForGlyph: g];
1418 w = max ([sfont advancementForGlyph: g].width, 2.0);
1419 metrics->width = lrint (w);
1422 rb = r.size.width - w;
1423 // Add to bearing for LCD smoothing. We don't know if it is there.
1425 metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1426 if (font_info->ital)
1427 rb += (CGFloat) (0.22F * font_info->height);
1428 metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1430 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1431 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1432 metrics->ascent = r.size.height - metrics->descent;
1433 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1439 #ifdef NS_IMPL_COCOA
1440 /* helper for font glyph setup */
1441 @implementation EmacsGlyphStorage
1445 return [self initWithCapacity: 1024];
1448 - initWithCapacity: (unsigned long) c
1450 self = [super init];
1453 dict = [NSMutableDictionary new];
1454 cglyphs = xmalloc (c * sizeof (CGGlyph));
1467 - (void) setString: (NSString *)str font: (NSFont *)font
1469 [dict setObject: font forKey: NSFontAttributeName];
1472 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1473 maxChar = [str length];
1477 /* NSGlyphStorage protocol */
1478 - (NSUInteger)layoutOptions
1483 - (NSAttributedString *)attributedString
1488 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1489 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1490 characterIndex: (NSUInteger)charIndex
1492 len = glyphIndex+length;
1493 for (i =glyphIndex; i<len; i++)
1494 cglyphs[i] = glyphs[i-glyphIndex];
1499 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1500 forGlyphAtIndex: (NSUInteger)glyphIndex
1506 #endif /* NS_IMPL_COCOA */
1511 ns_dump_glyphstring (struct glyph_string *s)
1515 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1516 "overlap = %d, bg_filled = %d:",
1517 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1518 s->row->overlapping_p, s->background_filled_p);
1519 for (i =0; i<s->nchars; i++)
1520 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1521 fprintf (stderr, "\n");
1526 syms_of_nsfont (void)
1528 nsfont_driver.type = Qns;
1529 register_font_driver (&nsfont_driver, NULL);
1530 DEFSYM (Qcondensed, "condensed");
1531 DEFSYM (Qexpanded, "expanded");
1532 DEFSYM (Qapple, "apple");
1533 DEFSYM (Qroman, "roman");
1534 DEFSYM (Qmedium, "medium");
1535 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1536 doc: /* Internal use: maps font registry to Unicode script. */);
1538 ascii_printable = NULL;