1 /* Font back-end driver for the NeXT/Open/GNUstep and macOS window system.
3 Copyright (C) 2006-2016 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 (at
10 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 /* font glyph and metrics caching functions, implemented at end */
49 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
51 static void ns_glyph_metrics (struct nsfont_info *font_info,
54 #define INVALID_GLYPH 0xFFFF
56 /* ==========================================================================
60 ========================================================================== */
63 /* Replace spaces w/another character so emacs core font parsing routines
66 ns_escape_name (char *name)
74 /* Reconstruct spaces in a font family name passed through emacs. */
76 ns_unescape_name (char *name)
84 /* Extract family name from a font spec. */
86 ns_get_family (Lisp_Object font_spec)
88 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
93 char *tmp = xlispstrdup (SYMBOL_NAME (tem));
95 ns_unescape_name (tmp);
96 family = [NSString stringWithUTF8String: tmp];
103 /* Return 0 if attr not set, else value (which might also be 0).
104 On Leopard 0 gets returned even on descriptors where the attribute
105 was never set, so there's no way to distinguish between unspecified
106 and set to not have. Callers should assume 0 means unspecified. */
108 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
110 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
111 NSNumber *val = [tdict objectForKey: trait];
112 return val == nil ? 0.0F : [val floatValue];
116 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
117 to NSFont descriptor. Information under extra only needed for matching. */
118 #define STYLE_REF 100
119 static NSFontDescriptor *
120 ns_spec_to_descriptor (Lisp_Object font_spec)
122 NSFontDescriptor *fdesc;
123 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
124 NSMutableDictionary *tdict = [NSMutableDictionary new];
125 NSString *family = ns_get_family (font_spec);
128 /* add each attr in font_spec to fdAttrs.. */
129 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
130 if (n != -1 && n != STYLE_REF)
131 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
132 forKey: NSFontWeightTrait];
133 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
134 if (n != -1 && n != STYLE_REF)
135 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
136 forKey: NSFontSlantTrait];
137 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
138 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
139 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
140 forKey: NSFontWidthTrait];
141 if ([tdict count] > 0)
142 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
144 fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
145 retain] autorelease];
149 NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
150 fdesc = [[fdesc2 retain] autorelease];
159 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
161 ns_descriptor_to_entity (NSFontDescriptor *desc,
165 Lisp_Object font_entity = font_make_entity ();
166 /* NSString *psName = [desc postscriptName]; */
167 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
168 unsigned int traits = [desc symbolicTraits];
171 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
173 family = [desc objectForKey: NSFontNameAttribute];
175 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
177 escapedFamily = xstrdup ([family UTF8String]);
178 ns_escape_name (escapedFamily);
180 ASET (font_entity, FONT_TYPE_INDEX, Qns);
181 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
182 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
183 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
184 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
186 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
187 traits & NSFontBoldTrait ? Qbold : Qmedium);
188 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
189 make_number (100 + 100
190 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
191 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
192 traits & NSFontItalicTrait ? Qitalic : Qnormal);
193 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
194 make_number (100 + 100
195 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
196 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
197 traits & NSFontCondensedTrait ? Qcondensed :
198 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
199 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
200 make_number (100 + 100
201 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
203 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
204 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
205 ASET (font_entity, FONT_SPACING_INDEX,
206 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
207 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
209 ASET (font_entity, FONT_EXTRA_INDEX, extra);
210 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
214 fprintf (stderr, "created font_entity:\n ");
215 debug_print (font_entity);
218 xfree (escapedFamily);
223 /* Default font entity. */
225 ns_fallback_entity (void)
227 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
228 fontDescriptor], Qnil, NULL);
232 /* Utility: get width of a char c in screen font SFONT */
234 ns_char_width (NSFont *sfont, int c)
237 NSString *cstr = [NSString stringWithFormat: @"%c", c];
240 NSGlyph glyph = [sfont glyphWithName: cstr];
242 w = [sfont advancementForGlyph: glyph].width;
247 NSDictionary *attrsDictionary =
248 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
249 w = [cstr sizeWithAttributes: attrsDictionary].width;
255 /* Return average width over ASCII printable characters for SFONT. */
257 static NSString *ascii_printable;
260 ns_ascii_average_width (NSFont *sfont)
264 if (!ascii_printable)
268 for (ch = 0; ch < 95; ch++)
269 chars[ch] = ' ' + ch;
272 ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
276 NSGlyph glyph = [sfont glyphWithName: ascii_printable];
278 w = [sfont advancementForGlyph: glyph].width;
281 if (w < (CGFloat) 0.0)
283 NSDictionary *attrsDictionary =
284 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
285 w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
288 return lrint (w / (CGFloat) 95.0);
292 /* Return whether set1 covers set2 to a reasonable extent given by pct.
293 We check, out of each 16 Unicode char range containing chars in set2,
294 whether at least one character is present in set1.
295 This must be true for pct of the pairs to consider it covering. */
297 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
299 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
300 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
301 int i, off = 0, tot = 0;
303 /* Work around what appears to be a GNUstep bug.
304 See <http://bugs.gnu.org/11853>. */
305 if (! (bytes1 && bytes2))
308 for (i=0; i<4096; i++, bytes1++, bytes2++)
312 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
315 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
316 return (float)off / tot < 1.0F - pct;
320 /* Convert :lang property to a script. Use of :lang property by font backend
321 seems to be limited for now (2009/05) to ja, zh, and ko. */
323 *ns_lang_to_script (Lisp_Object lang)
325 if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
327 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
328 have more characters. */
329 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
331 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
338 /* Convert OTF 4-letter script code to emacs script name. (Why can't
339 everyone just use some standard Unicode names for these?) */
341 *ns_otf_to_script (Lisp_Object otf)
343 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
344 return CONSP (script)
345 ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
350 /* Convert a font registry, such as */
352 *ns_registry_to_script (char *reg)
354 Lisp_Object script, r, rts = Vns_reg_to_script;
357 r = XCAR (XCAR (rts));
358 if (!strncmp (SSDATA (r), reg, SBYTES (r)))
360 script = XCDR (XCAR (rts));
361 return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
369 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
370 plus registry regular property, for something that can be mapped to a
371 Unicode script. Empty string returned if no script spec found. */
373 *ns_get_req_script (Lisp_Object font_spec)
375 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
376 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
378 /* The extra-bundle properties have priority. */
379 for ( ; CONSP (extra); extra = XCDR (extra))
381 Lisp_Object tmp = XCAR (extra);
384 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
385 if (EQ (key, QCscript) && SYMBOLP (val))
386 return [NSString stringWithUTF8String:
387 SSDATA (SYMBOL_NAME (val))];
388 if (EQ (key, QClang) && SYMBOLP (val))
389 return ns_lang_to_script (val);
390 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
391 return ns_otf_to_script (val);
395 /* If we get here, check the charset portion of the registry. */
398 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
399 (which causes box rendering if we don't treat it like iso8858-1)
400 but also for ascii (which causes unnecessary font substitution). */
402 if (EQ (reg, Qiso10646_1))
405 return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
412 /* This small function is static in fontset.c. If it can be made public for
413 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
415 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
417 if (EQ (XCAR (arg), val))
420 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
422 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
427 /* Use the Unicode range information in Vchar_script_table to convert a script
428 name into an NSCharacterSet. */
429 static NSCharacterSet
430 *ns_script_to_charset (NSString *scriptName)
432 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
433 Lisp_Object script = intern ([scriptName UTF8String]);
434 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
436 if (! NILP (Fmemq (script, script_list)))
438 Lisp_Object ranges, range_list;
440 ranges = list1 (script);
441 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
443 range_list = Fnreverse (XCDR (ranges));
444 if (! NILP (range_list))
446 for (; CONSP (range_list); range_list = XCDR (range_list))
448 int start = XINT (XCAR (XCAR (range_list)));
449 int end = XINT (XCDR (XCAR (range_list)));
451 debug_print (XCAR (range_list));
453 [charset addCharactersInRange:
454 NSMakeRange (start, end-start)];
462 /* Return an array of font families containing characters for the given
463 script, for the given coverage criterion, including at least LastResort.
464 Results are cached by script for faster access.
465 If none are found, we reduce the percentage and try again, until 5%.
466 This provides a font with at least some characters if such can be found.
467 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
468 (b) need approximate match as fonts covering full Unicode ranges are rare. */
470 *ns_get_covering_families (NSString *script, float pct)
472 static NSMutableDictionary *scriptToFamilies = nil;
473 NSMutableSet *families;
476 NSLog(@"Request covering families for script: '%@'", script);
478 if (scriptToFamilies == nil)
479 scriptToFamilies = [[NSMutableDictionary alloc] init];
481 if ((families = [scriptToFamilies objectForKey: script]) == nil)
483 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
484 NSArray *allFamilies = [fontMgr availableFontFamilies];
486 if ([script length] == 0)
487 families = [NSMutableSet setWithArray: allFamilies];
490 NSCharacterSet *charset = ns_script_to_charset (script);
492 families = [NSMutableSet setWithCapacity: 10];
495 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
496 while ((family = [allFamiliesEnum nextObject]))
498 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
499 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
500 /* Some fonts on macOS, maybe many on GNUstep, return nil. */
502 fset = [NSCharacterSet characterSetWithRange:
503 NSMakeRange (0, 127)];
504 if (ns_charset_covers(fset, charset, pct))
505 [families addObject: family];
508 if ([families count] > 0 || pct < 0.05F)
514 if ([families count] == 0)
515 [families addObject: @"LastResort"];
517 [scriptToFamilies setObject: families forKey: script];
521 NSLog(@" returning %lu families", (unsigned long)[families count]);
526 /* Implementation for list() and match(). List() can return nil, match()
527 must return something. Strategy is to drop family name from attribute
528 matching set for match. */
530 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
532 Lisp_Object tem, list = Qnil;
533 NSFontDescriptor *fdesc, *desc;
535 NSArray *matchingDescs;
544 fprintf (stderr, "nsfont: %s for fontspec:\n ",
545 (isMatch ? "match" : "list"));
546 debug_print (font_spec);
549 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
551 fdesc = ns_spec_to_descriptor (font_spec);
552 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
554 [fkeys removeObject: NSFontFamilyAttribute];
556 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
559 NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
560 (unsigned long)[matchingDescs count]);
562 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
564 if (![cFamilies containsObject:
565 [desc objectForKey: NSFontFamilyAttribute]])
567 tem = ns_descriptor_to_entity (desc,
568 AREF (font_spec, FONT_EXTRA_INDEX),
572 list = Fcons (tem, list);
573 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
577 /* Add synthItal member if needed. */
578 family = [fdesc objectForKey: NSFontFamilyAttribute];
579 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
581 NSFontDescriptor *s1 = [NSFontDescriptor new];
582 NSFontDescriptor *sDesc
583 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
584 fontDescriptorWithFamily: family];
585 list = Fcons (ns_descriptor_to_entity (sDesc,
586 AREF (font_spec, FONT_EXTRA_INDEX),
593 /* Return something if was a match and nothing found. */
595 return ns_fallback_entity ();
598 fprintf (stderr, " Returning %"pI"d entities.\n",
599 XINT (Flength (list)));
606 /* ==========================================================================
608 Font driver implementation
610 ========================================================================== */
613 static Lisp_Object nsfont_get_cache (struct frame *frame);
614 static Lisp_Object nsfont_list (struct frame *, Lisp_Object);
615 static Lisp_Object nsfont_match (struct frame *, Lisp_Object);
616 static Lisp_Object nsfont_list_family (struct frame *);
617 static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity,
619 static void nsfont_close (struct font *font);
620 static int nsfont_has_char (Lisp_Object entity, int c);
621 static unsigned int nsfont_encode_char (struct font *font, int c);
622 static void nsfont_text_extents (struct font *font, unsigned int *code,
623 int nglyphs, struct font_metrics *metrics);
624 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
625 bool with_background);
627 struct font_driver nsfont_driver =
630 1, /* case sensitive */
635 NULL, /*free_entity */
638 NULL, /* prepare_face */
639 NULL, /* done_face */
644 /* excluded: get_bitmap, free_bitmap,
645 anchor_point, otf_capability, otf_driver,
646 start_for_frame, end_for_frame, shape */
650 /* Return a cache of font-entities on FRAME. The cache must be a
651 cons whose cdr part is the actual cache area. */
653 nsfont_get_cache (struct frame *frame)
655 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (frame);
656 return (dpyinfo->name_list_element);
660 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
661 **list** of font-entities. This and match () are sole APIs that allocate
662 font-entities. Properties to be considered (2009/05/19) are:
663 regular: foundry, family, adstyle, registry
664 extended: script, lang, otf
665 "Extended" properties are not part of the vector but get stored as
666 lisp properties under FONT_EXTRA_INDEX.
668 The returned entities should have type set (to 'ns), plus the following:
669 foundry, family, adstyle, registry,
670 weight, slant, width, size (0 if scalable),
671 dpi, spacing, avgwidth (0 if scalable) */
673 nsfont_list (struct frame *f, Lisp_Object font_spec)
675 return ns_findfonts (font_spec, NO);
679 /* Return a font entity most closely matching with FONT_SPEC on
680 FRAME. The closeness is determined by the font backend, thus
681 `face-font-selection-order' is ignored here.
682 Properties to be considered are same as for list(). */
684 nsfont_match (struct frame *f, Lisp_Object font_spec)
686 return ns_findfonts (font_spec, YES);
690 /* List available families. The value is a list of family names
693 nsfont_list_family (struct frame *f)
695 Lisp_Object list = Qnil;
696 NSEnumerator *families;
700 families = [[[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)));
715 /* Open a font specified by FONT_ENTITY on frame F. If the font is
716 scalable, open it with PIXEL_SIZE. */
718 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
721 unsigned int traits = 0;
722 struct nsfont_info *font_info;
724 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
725 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
727 NSFont *nsfont, *sfont;
730 Lisp_Object font_object;
737 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
738 debug_print (font_entity);
743 /* try to get it out of frame params */
744 Lisp_Object tem = get_frame_param (f, Qfontsize);
745 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
748 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
749 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
751 family = ns_get_family (font_entity);
753 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
754 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
755 when setting family in ns_spec_to_descriptor(). */
756 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
757 traits |= NSBoldFontMask;
758 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
759 traits |= NSItalicFontMask;
761 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
762 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
763 nsfont = [fontMgr fontWithFamily: family
764 traits: traits weight: fixLeopardBug
766 /* if didn't find, try synthetic italic */
767 if (nsfont == nil && synthItal)
769 nsfont = [fontMgr fontWithFamily: family
770 traits: traits & ~NSItalicFontMask
771 weight: fixLeopardBug size: pixel_size];
774 /* LastResort not really a family */
775 if (nsfont == nil && [@"LastResort" isEqualToString: family])
776 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
781 message_with_string ("*** Warning: font in family `%s' not found",
782 build_string ([family UTF8String]), 1);
783 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
787 NSLog (@"%@\n", nsfont);
789 font_object = font_make_object (VECSIZE (struct nsfont_info),
790 font_entity, pixel_size);
791 ASET (font_object, FONT_TYPE_INDEX, nsfont_driver.type);
792 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
793 font = (struct font *) font_info;
797 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
800 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
801 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;
826 const char *fontName = [[nsfont fontName] UTF8String];
828 /* The values specified by fonts are not always exact. For
829 * example, a 6x8 font could specify that the descender is
830 * -2.00000405... (represented by 0xc000000220000000). Without
831 * adjustment, the code below would round the descender to -3,
832 * resulting in a font that would be one pixel higher than
834 CGFloat adjusted_descender = [sfont descender] + 0.0001;
836 #ifdef NS_IMPL_GNUSTEP
837 font_info->nsfont = sfont;
839 font_info->nsfont = nsfont;
841 [font_info->nsfont retain];
843 /* set up ns_font (defined in nsgui.h) */
844 font_info->name = xstrdup (fontName);
845 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
847 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
849 /* Metrics etc.; some fonts return an unusually large max advance, so we
850 only use it for fonts that have wide characters. */
851 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
852 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
854 brect = [sfont boundingRectForFont];
856 font_info->underpos = [sfont underlinePosition];
857 font_info->underwidth = [sfont underlineThickness];
858 font_info->size = font->pixel_size;
861 font->ascent = font_info->max_bounds.ascent = lrint ([sfont ascender]);
862 /* Descender is usually negative. Use floor to avoid
863 clipping descenders. */
865 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
867 font_info->max_bounds.ascent + font_info->max_bounds.descent;
868 font_info->max_bounds.width = lrint (font_info->width);
869 font_info->max_bounds.lbearing = lrint (brect.origin.x);
870 font_info->max_bounds.rbearing =
871 lrint (brect.size.width - (CGFloat) font_info->width);
874 /* set up synthItal and the CG font */
875 font_info->synthItal = synthItal;
877 ATSFontRef atsFont = ATSFontFindFromPostScriptName
878 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
880 if (atsFont == kATSFontRefUnspecified)
882 /* see if we can get it by dropping italic (then synthesizing) */
883 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
884 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
885 fontName], kATSOptionFlagsDefault);
886 if (atsFont != kATSFontRefUnspecified)
887 font_info->synthItal = YES;
890 /* last resort fallback */
891 atsFont = ATSFontFindFromPostScriptName
892 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
895 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
899 /* set up metrics portion of font struct */
900 font->ascent = lrint([sfont ascender]);
901 font->descent = -lrint(floor(adjusted_descender));
902 font->space_width = lrint (ns_char_width (sfont, ' '));
903 font->max_width = lrint (font_info->max_bounds.width);
904 font->min_width = font->space_width; /* Approximate. */
905 font->average_width = ns_ascii_average_width (sfont);
907 font->height = lrint (font_info->height);
908 font->underline_position = lrint (font_info->underpos);
909 font->underline_thickness = lrint (font_info->underwidth);
911 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
912 font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
922 nsfont_close (struct font *font)
924 struct nsfont_info *font_info = (struct nsfont_info *) font;
926 /* FIXME: font_info may be NULL due to same failure to detect
927 same font that causes need for cache in nsfont_open. */
928 if (font_info && font_info->name)
932 for (i = 0; i < 0x100; i++)
934 xfree (font_info->glyphs[i]);
935 xfree (font_info->metrics[i]);
937 xfree (font_info->glyphs);
938 xfree (font_info->metrics);
939 [font_info->nsfont release];
941 CGFontRelease (font_info->cgfont);
943 xfree (font_info->name);
944 font_info->name = NULL;
949 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
950 return 1. If not, return 0. If a font must be opened to check
953 nsfont_has_char (Lisp_Object entity, int c)
959 /* Return a glyph code of FONT for character C (Unicode code point).
960 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
962 nsfont_encode_char (struct font *font, int c)
964 struct nsfont_info *font_info = (struct nsfont_info *)font;
965 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
969 return FONT_INVALID_CODE;
971 /* did we already cache this block? */
972 if (!font_info->glyphs[high])
973 ns_uni_to_glyphs (font_info, high);
975 g = font_info->glyphs[high][low];
976 return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
980 /* Perform the size computation of glyphs of FONT and fill in members
981 of METRICS. The glyphs are specified by their glyph codes in
982 CODE (length NGLYPHS). */
984 nsfont_text_extents (struct font *font, unsigned int *code,
985 int nglyphs, struct font_metrics *metrics)
987 struct nsfont_info *font_info = (struct nsfont_info *)font;
988 struct font_metrics *pcm;
989 unsigned char high, low;
993 memset (metrics, 0, sizeof (struct font_metrics));
995 for (i = 0; i < nglyphs; i++)
997 /* get metrics for this glyph, filling cache if need be */
998 /* TODO: get metrics for whole string from an NSLayoutManager
1000 high = (code[i] & 0xFF00) >> 8;
1001 low = code[i] & 0x00FF;
1002 if (!font_info->metrics[high])
1003 ns_glyph_metrics (font_info, high);
1004 pcm = &(font_info->metrics[high][low]);
1006 if (metrics->lbearing > totalWidth + pcm->lbearing)
1007 metrics->lbearing = totalWidth + pcm->lbearing;
1008 if (metrics->rbearing < totalWidth + pcm->rbearing)
1009 metrics->rbearing = totalWidth + pcm->rbearing;
1010 if (metrics->ascent < pcm->ascent)
1011 metrics->ascent = pcm->ascent;
1012 if (metrics->descent < pcm->descent)
1013 metrics->descent = pcm->descent;
1015 totalWidth += pcm->width;
1018 metrics->width = totalWidth;
1022 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1023 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1024 fill the background in advance. It is assured that WITH_BACKGROUND
1025 is false when (FROM > 0 || TO < S->nchars). */
1027 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1028 bool with_background)
1029 /* NOTE: focus and clip must be set */
1031 static unsigned char cbuf[1024];
1032 unsigned char *c = cbuf;
1033 #ifdef NS_IMPL_GNUSTEP
1034 #if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22
1035 static CGFloat advances[1024];
1036 CGFloat *adv = advances;
1038 static float advances[1024];
1039 float *adv = advances;
1042 static CGSize advances[1024];
1043 CGSize *adv = advances;
1047 struct nsfont_info *font;
1048 NSColor *col, *bgCol;
1049 unsigned short *t = s->char2b;
1051 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1055 font = (struct nsfont_info *)s->face->font;
1057 font = (struct nsfont_info *)FRAME_FONT (s->f);
1059 /* Select face based on input flags */
1060 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
1061 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
1062 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
1063 NS_DUMPGLYPH_NORMAL));
1067 case NS_DUMPGLYPH_CURSOR:
1070 case NS_DUMPGLYPH_MOUSEFACE:
1071 face = FACE_FROM_ID_OR_NULL (s->f,
1072 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1074 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1081 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1082 r.origin.x += abs (s->face->box_line_width);
1085 r.size.height = FONT_HEIGHT (font);
1087 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1088 NS to render the string, it will come out differently from the individual
1089 character widths added up because of layout processing. */
1091 int cwidth, twidth = 0;
1093 /* FIXME: composition: no vertical displacement is considered. */
1094 t += from; /* advance into composition */
1095 for (i = from; i < to; i++, t++)
1097 hi = (*t & 0xFF00) >> 8;
1101 if (!s->first_glyph->u.cmp.automatic)
1102 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1105 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1106 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1107 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1108 cwidth = LGLYPH_WIDTH (glyph);
1111 cwidth = LGLYPH_WADJUST (glyph);
1112 #ifdef NS_IMPL_GNUSTEP
1113 *(adv-1) += LGLYPH_XOFF (glyph);
1115 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1122 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1123 ns_glyph_metrics (font, hi);
1124 cwidth = font->metrics[hi][lo].width;
1127 #ifdef NS_IMPL_GNUSTEP
1129 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1131 (*adv++).width = cwidth;
1134 len = adv - advances;
1135 r.size.width = twidth;
1139 /* fill background if requested */
1140 if (with_background && !isComposite)
1143 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1144 int mbox_line_width = max (s->face->box_line_width, 0);
1146 if (s->row->full_width_p)
1148 if (br.origin.x <= fibw + 1 + mbox_line_width)
1150 br.size.width += br.origin.x - mbox_line_width;
1151 br.origin.x = mbox_line_width;
1153 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1155 br.size.width += fibw;
1157 if (s->face->box == FACE_NO_BOX)
1159 /* expand unboxed top row over internal border */
1160 if (br.origin.y <= fibw + 1 + mbox_line_width)
1162 br.size.height += br.origin.y;
1168 int correction = abs (s->face->box_line_width)+1;
1169 br.origin.y += correction;
1170 br.size.height -= 2*correction;
1171 br.origin.x += correction;
1172 br.size.width -= 2*correction;
1175 if (!s->face->stipple)
1176 [(NS_FACE_BACKGROUND (face) != 0
1177 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1178 : FRAME_BACKGROUND_COLOR (s->f)) set];
1181 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
1182 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1188 /* set up for character rendering */
1191 col = (NS_FACE_FOREGROUND (face) != 0
1192 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1193 : FRAME_FOREGROUND_COLOR (s->f));
1195 bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
1196 : (NS_FACE_BACKGROUND (face) != 0
1197 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1198 : FRAME_BACKGROUND_COLOR (s->f)));
1200 /* render under GNUstep using DPS */
1201 #ifdef NS_IMPL_GNUSTEP
1203 NSGraphicsContext *context = GSCurrentContext ();
1208 /* do erase if "foreground" mode */
1212 DPSmoveto (context, r.origin.x, r.origin.y);
1213 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1214 DPSxshow (context, (const char *) cbuf, advances, len);
1215 DPSstroke (context);
1217 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1222 /* draw with DPSxshow () */
1223 DPSmoveto (context, r.origin.x, r.origin.y);
1224 DPSxshow (context, (const char *) cbuf, advances, len);
1225 DPSstroke (context);
1227 DPSgrestore (context);
1230 #else /* NS_IMPL_COCOA */
1232 CGContextRef gcontext =
1233 [[NSGraphicsContext currentContext] graphicsPort];
1234 static CGAffineTransform fliptf;
1235 static BOOL firstTime = YES;
1240 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1243 CGContextSaveGState (gcontext);
1245 // Used to be Fix2X (kATSItalicQDSkew), but Fix2X is deprecated
1246 // and kATSItalicQDSkew is 0.25.
1247 fliptf.c = font->synthItal ? 0.25 : 0.0;
1249 CGContextSetFont (gcontext, font->cgfont);
1250 CGContextSetFontSize (gcontext, font->size);
1251 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1252 CGContextSetShouldAntialias (gcontext, 0);
1254 CGContextSetShouldAntialias (gcontext, 1);
1256 CGContextSetTextMatrix (gcontext, fliptf);
1260 /* foreground drawing; erase first to avoid overstrike */
1262 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1263 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1264 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1265 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1270 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1271 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1274 if (face->overstrike)
1276 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1277 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1281 CGContextRestoreGState (gcontext);
1283 #endif /* NS_IMPL_COCOA */
1291 /* ==========================================================================
1293 Font glyph and metrics caching functions
1295 ========================================================================== */
1297 /* Find and cache corresponding glyph codes for unicode values in given
1298 hi-byte block of 256. */
1300 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1302 #ifdef NS_IMPL_COCOA
1303 static EmacsGlyphStorage *glyphStorage;
1304 static char firstTime = 1;
1306 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1307 unsigned int i, g, idx;
1308 unsigned short *glyphs;
1311 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1316 #ifdef NS_IMPL_COCOA
1320 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1324 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1325 if (!unichars || !(font_info->glyphs[block]))
1328 /* create a string containing all Unicode characters in this block */
1329 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1330 if (idx < 0xD800 || idx > 0xDFFF)
1333 unichars[i] = 0xFEFF;
1334 unichars[0x100] = 0;
1337 #ifdef NS_IMPL_COCOA
1338 NSString *allChars = [[NSString alloc]
1339 initWithCharactersNoCopy: unichars
1342 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1343 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1344 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1345 NSUInteger gInd = 0, cInd = 0;
1347 [glyphStorage setString: allChars font: font_info->nsfont];
1348 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1349 desiredNumberOfCharacters: glyphStorage->maxChar
1350 glyphIndex: &gInd characterIndex: &cInd];
1352 glyphs = font_info->glyphs[block];
1353 for (i = 0; i < 0x100; i++, glyphs++)
1355 #ifdef NS_IMPL_GNUSTEP
1358 g = glyphStorage->cglyphs[i];
1359 /* TODO: is this a good check? maybe need to use coveredChars.. */
1360 if (g > numGlyphs || g == NSNullGlyph)
1361 g = INVALID_GLYPH; /* hopefully unused... */
1366 #ifdef NS_IMPL_COCOA
1376 /* Determine and cache metrics for corresponding glyph codes in given
1377 hi-byte block of 256. */
1379 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1382 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1384 struct font_metrics *metrics;
1387 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1390 #ifdef NS_IMPL_GNUSTEP
1391 /* not implemented yet (as of startup 0.18), so punt */
1393 numGlyphs = 0x10000;
1397 #ifdef NS_IMPL_COCOA
1398 sfont = [font_info->nsfont screenFontWithRenderingMode:
1399 NSFontAntialiasedIntegerAdvancementsRenderingMode];
1401 sfont = [font_info->nsfont screenFont];
1404 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1405 if (!(font_info->metrics[block]))
1408 metrics = font_info->metrics[block];
1409 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1412 NSRect r = [sfont boundingRectForGlyph: g];
1414 w = max ([sfont advancementForGlyph: g].width, 2.0);
1415 metrics->width = lrint (w);
1418 rb = r.size.width - w;
1419 // Add to bearing for LCD smoothing. We don't know if it is there.
1421 metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1422 if (font_info->ital)
1423 rb += (CGFloat) (0.22F * font_info->height);
1424 metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
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++)
1517 int c = s->first_glyph[i].u.ch;
1518 fprintf (stderr, "%c", c);
1520 fprintf (stderr, "\n");
1525 syms_of_nsfont (void)
1527 nsfont_driver.type = Qns;
1528 register_font_driver (&nsfont_driver, NULL);
1529 DEFSYM (Qcondensed, "condensed");
1530 DEFSYM (Qexpanded, "expanded");
1531 DEFSYM (Qapple, "apple");
1532 DEFSYM (Qmedium, "medium");
1533 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1534 doc: /* Internal use: maps font registry to Unicode script. */);
1536 ascii_printable = NULL;