1 /* Font back-end driver for the NeXT/Open/GNUstep and macOS window system.
3 Copyright (C) 2006-2017 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 /* Return a cache of font-entities on FRAME. The cache must be a
614 cons whose cdr part is the actual cache area. */
616 nsfont_get_cache (struct frame *frame)
618 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (frame);
619 return (dpyinfo->name_list_element);
623 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
624 **list** of font-entities. This and match () are sole APIs that allocate
625 font-entities. Properties to be considered (2009/05/19) are:
626 regular: foundry, family, adstyle, registry
627 extended: script, lang, otf
628 "Extended" properties are not part of the vector but get stored as
629 lisp properties under FONT_EXTRA_INDEX.
631 The returned entities should have type set (to 'ns), plus the following:
632 foundry, family, adstyle, registry,
633 weight, slant, width, size (0 if scalable),
634 dpi, spacing, avgwidth (0 if scalable) */
636 nsfont_list (struct frame *f, Lisp_Object font_spec)
638 return ns_findfonts (font_spec, NO);
642 /* Return a font entity most closely matching with FONT_SPEC on
643 FRAME. The closeness is determined by the font backend, thus
644 `face-font-selection-order' is ignored here.
645 Properties to be considered are same as for list(). */
647 nsfont_match (struct frame *f, Lisp_Object font_spec)
649 return ns_findfonts (font_spec, YES);
653 /* List available families. The value is a list of family names
656 nsfont_list_family (struct frame *f)
658 Lisp_Object list = Qnil;
659 NSEnumerator *families;
663 families = [[[NSFontManager sharedFontManager] availableFontFamilies]
665 while ((family = [families nextObject]))
666 list = Fcons (intern ([family UTF8String]), list);
667 /* FIXME: escape the name? */
670 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
671 XINT (Flength (list)));
678 /* Open a font specified by FONT_ENTITY on frame F. If the font is
679 scalable, open it with PIXEL_SIZE. */
681 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
684 unsigned int traits = 0;
685 struct nsfont_info *font_info;
687 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
688 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
690 NSFont *nsfont, *sfont;
693 Lisp_Object font_object;
700 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
701 debug_print (font_entity);
706 /* try to get it out of frame params */
707 Lisp_Object tem = get_frame_param (f, Qfontsize);
708 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
711 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
712 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
714 family = ns_get_family (font_entity);
716 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
717 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
718 when setting family in ns_spec_to_descriptor(). */
719 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
720 traits |= NSBoldFontMask;
721 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
722 traits |= NSItalicFontMask;
724 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
725 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
726 nsfont = [fontMgr fontWithFamily: family
727 traits: traits weight: fixLeopardBug
729 /* if didn't find, try synthetic italic */
730 if (nsfont == nil && synthItal)
732 nsfont = [fontMgr fontWithFamily: family
733 traits: traits & ~NSItalicFontMask
734 weight: fixLeopardBug size: pixel_size];
737 /* LastResort not really a family */
738 if (nsfont == nil && [@"LastResort" isEqualToString: family])
739 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
744 message_with_string ("*** Warning: font in family `%s' not found",
745 build_string ([family UTF8String]), 1);
746 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
750 NSLog (@"%@\n", nsfont);
752 font_object = font_make_object (VECSIZE (struct nsfont_info),
753 font_entity, pixel_size);
754 ASET (font_object, FONT_TYPE_INDEX, Qns);
755 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
756 font = (struct font *) font_info;
760 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
763 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
764 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
768 sfont = [nsfont screenFontWithRenderingMode:
769 NSFontAntialiasedIntegerAdvancementsRenderingMode];
771 sfont = [nsfont screenFont];
777 /* non-metric backend font struct fields */
778 font = (struct font *) font_info;
779 font->pixel_size = [sfont pointSize];
780 font->driver = &nsfont_driver;
781 font->encoding_charset = -1;
782 font->repertory_charset = -1;
783 font->default_ascent = 0;
784 font->vertical_centering = 0;
785 font->baseline_offset = 0;
786 font->relative_compose = 0;
789 const char *fontName = [[nsfont fontName] UTF8String];
791 /* The values specified by fonts are not always exact. For
792 * example, a 6x8 font could specify that the descender is
793 * -2.00000405... (represented by 0xc000000220000000). Without
794 * adjustment, the code below would round the descender to -3,
795 * resulting in a font that would be one pixel higher than
797 CGFloat adjusted_descender = [sfont descender] + 0.0001;
799 #ifdef NS_IMPL_GNUSTEP
800 font_info->nsfont = sfont;
802 font_info->nsfont = nsfont;
804 [font_info->nsfont retain];
806 /* set up ns_font (defined in nsgui.h) */
807 font_info->name = xstrdup (fontName);
808 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
810 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
812 /* Metrics etc.; some fonts return an unusually large max advance, so we
813 only use it for fonts that have wide characters. */
814 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
815 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
817 brect = [sfont boundingRectForFont];
819 font_info->underpos = [sfont underlinePosition];
820 font_info->underwidth = [sfont underlineThickness];
821 font_info->size = font->pixel_size;
824 font->ascent = font_info->max_bounds.ascent = lrint ([sfont ascender]);
825 /* Descender is usually negative. Use floor to avoid
826 clipping descenders. */
828 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
830 font_info->max_bounds.ascent + font_info->max_bounds.descent;
831 font_info->max_bounds.width = lrint (font_info->width);
832 font_info->max_bounds.lbearing = lrint (brect.origin.x);
833 font_info->max_bounds.rbearing =
834 lrint (brect.size.width - (CGFloat) font_info->width);
837 /* set up synthItal and the CG font */
838 font_info->synthItal = synthItal;
840 ATSFontRef atsFont = ATSFontFindFromPostScriptName
841 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
843 if (atsFont == kATSFontRefUnspecified)
845 /* see if we can get it by dropping italic (then synthesizing) */
846 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
847 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
848 fontName], kATSOptionFlagsDefault);
849 if (atsFont != kATSFontRefUnspecified)
850 font_info->synthItal = YES;
853 /* last resort fallback */
854 atsFont = ATSFontFindFromPostScriptName
855 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
858 font_info->cgfont = CGFontCreateWithPlatformFont ((void *) &atsFont);
862 /* set up metrics portion of font struct */
863 font->ascent = lrint([sfont ascender]);
864 font->descent = -lrint(floor(adjusted_descender));
865 font->space_width = lrint (ns_char_width (sfont, ' '));
866 font->max_width = lrint (font_info->max_bounds.width);
867 font->min_width = font->space_width; /* Approximate. */
868 font->average_width = ns_ascii_average_width (sfont);
870 font->height = lrint (font_info->height);
871 font->underline_position = lrint (font_info->underpos);
872 font->underline_thickness = lrint (font_info->underwidth);
874 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
875 font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
885 nsfont_close (struct font *font)
887 struct nsfont_info *font_info = (struct nsfont_info *) font;
889 /* FIXME: font_info may be NULL due to same failure to detect
890 same font that causes need for cache in nsfont_open. */
891 if (font_info && font_info->name)
895 for (i = 0; i < 0x100; i++)
897 xfree (font_info->glyphs[i]);
898 xfree (font_info->metrics[i]);
900 xfree (font_info->glyphs);
901 xfree (font_info->metrics);
902 [font_info->nsfont release];
904 CGFontRelease (font_info->cgfont);
906 xfree (font_info->name);
907 font_info->name = NULL;
912 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
913 return 1. If not, return 0. If a font must be opened to check
916 nsfont_has_char (Lisp_Object entity, int c)
922 /* Return a glyph code of FONT for character C (Unicode code point).
923 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
925 nsfont_encode_char (struct font *font, int c)
927 struct nsfont_info *font_info = (struct nsfont_info *)font;
928 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
932 return FONT_INVALID_CODE;
934 /* did we already cache this block? */
935 if (!font_info->glyphs[high])
936 ns_uni_to_glyphs (font_info, high);
938 g = font_info->glyphs[high][low];
939 return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
943 /* Perform the size computation of glyphs of FONT and fill in members
944 of METRICS. The glyphs are specified by their glyph codes in
945 CODE (length NGLYPHS). */
947 nsfont_text_extents (struct font *font, unsigned int *code,
948 int nglyphs, struct font_metrics *metrics)
950 struct nsfont_info *font_info = (struct nsfont_info *)font;
951 struct font_metrics *pcm;
952 unsigned char high, low;
956 memset (metrics, 0, sizeof (struct font_metrics));
958 for (i = 0; i < nglyphs; i++)
960 /* get metrics for this glyph, filling cache if need be */
961 /* TODO: get metrics for whole string from an NSLayoutManager
963 high = (code[i] & 0xFF00) >> 8;
964 low = code[i] & 0x00FF;
965 if (!font_info->metrics[high])
966 ns_glyph_metrics (font_info, high);
967 pcm = &(font_info->metrics[high][low]);
969 if (metrics->lbearing > totalWidth + pcm->lbearing)
970 metrics->lbearing = totalWidth + pcm->lbearing;
971 if (metrics->rbearing < totalWidth + pcm->rbearing)
972 metrics->rbearing = totalWidth + pcm->rbearing;
973 if (metrics->ascent < pcm->ascent)
974 metrics->ascent = pcm->ascent;
975 if (metrics->descent < pcm->descent)
976 metrics->descent = pcm->descent;
978 totalWidth += pcm->width;
981 metrics->width = totalWidth;
985 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
986 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
987 fill the background in advance. It is assured that WITH_BACKGROUND
988 is false when (FROM > 0 || TO < S->nchars). */
990 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
991 bool with_background)
992 /* NOTE: focus and clip must be set */
994 static unsigned char cbuf[1024];
995 unsigned char *c = cbuf;
996 #ifdef NS_IMPL_GNUSTEP
997 #if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22
998 static CGFloat advances[1024];
999 CGFloat *adv = advances;
1001 static float advances[1024];
1002 float *adv = advances;
1005 static CGSize advances[1024];
1006 CGSize *adv = advances;
1010 struct nsfont_info *font;
1011 NSColor *col, *bgCol;
1012 unsigned short *t = s->char2b;
1014 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1018 font = (struct nsfont_info *)s->face->font;
1020 font = (struct nsfont_info *)FRAME_FONT (s->f);
1022 /* Select face based on input flags */
1023 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
1024 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
1025 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
1026 NS_DUMPGLYPH_NORMAL));
1030 case NS_DUMPGLYPH_CURSOR:
1033 case NS_DUMPGLYPH_MOUSEFACE:
1034 face = FACE_FROM_ID_OR_NULL (s->f,
1035 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1037 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1044 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1045 r.origin.x += abs (s->face->box_line_width);
1048 r.size.height = FONT_HEIGHT (font);
1050 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1051 NS to render the string, it will come out differently from the individual
1052 character widths added up because of layout processing. */
1054 int cwidth, twidth = 0;
1056 /* FIXME: composition: no vertical displacement is considered. */
1057 t += from; /* advance into composition */
1058 for (i = from; i < to; i++, t++)
1060 hi = (*t & 0xFF00) >> 8;
1064 if (!s->first_glyph->u.cmp.automatic)
1065 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1068 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1069 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1070 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1071 cwidth = LGLYPH_WIDTH (glyph);
1074 cwidth = LGLYPH_WADJUST (glyph);
1075 #ifdef NS_IMPL_GNUSTEP
1076 *(adv-1) += LGLYPH_XOFF (glyph);
1078 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1085 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1086 ns_glyph_metrics (font, hi);
1087 cwidth = font->metrics[hi][lo].width;
1090 #ifdef NS_IMPL_GNUSTEP
1092 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1094 (*adv++).width = cwidth;
1097 len = adv - advances;
1098 r.size.width = twidth;
1102 /* fill background if requested */
1103 if (with_background && !isComposite)
1106 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1107 int mbox_line_width = max (s->face->box_line_width, 0);
1109 if (s->row->full_width_p)
1111 if (br.origin.x <= fibw + 1 + mbox_line_width)
1113 br.size.width += br.origin.x - mbox_line_width;
1114 br.origin.x = mbox_line_width;
1116 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1118 br.size.width += fibw;
1120 if (s->face->box == FACE_NO_BOX)
1122 /* expand unboxed top row over internal border */
1123 if (br.origin.y <= fibw + 1 + mbox_line_width)
1125 br.size.height += br.origin.y;
1131 int correction = abs (s->face->box_line_width)+1;
1132 br.origin.y += correction;
1133 br.size.height -= 2*correction;
1134 br.origin.x += correction;
1135 br.size.width -= 2*correction;
1138 if (!s->face->stipple)
1139 [(NS_FACE_BACKGROUND (face) != 0
1140 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1141 : FRAME_BACKGROUND_COLOR (s->f)) set];
1144 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
1145 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1151 /* set up for character rendering */
1154 col = (NS_FACE_FOREGROUND (face) != 0
1155 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1156 : FRAME_FOREGROUND_COLOR (s->f));
1158 bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
1159 : (NS_FACE_BACKGROUND (face) != 0
1160 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1161 : FRAME_BACKGROUND_COLOR (s->f)));
1163 /* render under GNUstep using DPS */
1164 #ifdef NS_IMPL_GNUSTEP
1166 NSGraphicsContext *context = GSCurrentContext ();
1171 /* do erase if "foreground" mode */
1175 DPSmoveto (context, r.origin.x, r.origin.y);
1176 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1177 DPSxshow (context, (const char *) cbuf, advances, len);
1178 DPSstroke (context);
1180 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1185 /* draw with DPSxshow () */
1186 DPSmoveto (context, r.origin.x, r.origin.y);
1187 DPSxshow (context, (const char *) cbuf, advances, len);
1188 DPSstroke (context);
1190 DPSgrestore (context);
1193 #else /* NS_IMPL_COCOA */
1195 CGContextRef gcontext =
1196 [[NSGraphicsContext currentContext] graphicsPort];
1197 static CGAffineTransform fliptf;
1198 static BOOL firstTime = YES;
1203 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1206 CGContextSaveGState (gcontext);
1208 // Used to be Fix2X (kATSItalicQDSkew), but Fix2X is deprecated
1209 // and kATSItalicQDSkew is 0.25.
1210 fliptf.c = font->synthItal ? 0.25 : 0.0;
1212 CGContextSetFont (gcontext, font->cgfont);
1213 CGContextSetFontSize (gcontext, font->size);
1214 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1215 CGContextSetShouldAntialias (gcontext, 0);
1217 CGContextSetShouldAntialias (gcontext, 1);
1219 CGContextSetTextMatrix (gcontext, fliptf);
1223 /* foreground drawing; erase first to avoid overstrike */
1225 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1226 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1227 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1228 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1233 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1234 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1237 if (face->overstrike)
1239 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1240 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1244 CGContextRestoreGState (gcontext);
1246 #endif /* NS_IMPL_COCOA */
1254 /* ==========================================================================
1256 Font glyph and metrics caching functions
1258 ========================================================================== */
1260 /* Find and cache corresponding glyph codes for unicode values in given
1261 hi-byte block of 256. */
1263 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1265 #ifdef NS_IMPL_COCOA
1266 static EmacsGlyphStorage *glyphStorage;
1267 static char firstTime = 1;
1269 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1270 unsigned int i, g, idx;
1271 unsigned short *glyphs;
1274 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1279 #ifdef NS_IMPL_COCOA
1283 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1287 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1288 if (!unichars || !(font_info->glyphs[block]))
1291 /* create a string containing all Unicode characters in this block */
1292 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1293 if (idx < 0xD800 || idx > 0xDFFF)
1296 unichars[i] = 0xFEFF;
1297 unichars[0x100] = 0;
1300 #ifdef NS_IMPL_COCOA
1301 NSString *allChars = [[NSString alloc]
1302 initWithCharactersNoCopy: unichars
1305 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1306 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1307 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1308 NSUInteger gInd = 0, cInd = 0;
1310 [glyphStorage setString: allChars font: font_info->nsfont];
1311 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1312 desiredNumberOfCharacters: glyphStorage->maxChar
1313 glyphIndex: &gInd characterIndex: &cInd];
1315 glyphs = font_info->glyphs[block];
1316 for (i = 0; i < 0x100; i++, glyphs++)
1318 #ifdef NS_IMPL_GNUSTEP
1321 g = glyphStorage->cglyphs[i];
1322 /* TODO: is this a good check? maybe need to use coveredChars.. */
1323 if (g > numGlyphs || g == NSNullGlyph)
1324 g = INVALID_GLYPH; /* hopefully unused... */
1329 #ifdef NS_IMPL_COCOA
1339 /* Determine and cache metrics for corresponding glyph codes in given
1340 hi-byte block of 256. */
1342 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1345 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1347 struct font_metrics *metrics;
1350 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1353 #ifdef NS_IMPL_GNUSTEP
1354 /* not implemented yet (as of startup 0.18), so punt */
1356 numGlyphs = 0x10000;
1360 #ifdef NS_IMPL_COCOA
1361 sfont = [font_info->nsfont screenFontWithRenderingMode:
1362 NSFontAntialiasedIntegerAdvancementsRenderingMode];
1364 sfont = [font_info->nsfont screenFont];
1367 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1368 if (!(font_info->metrics[block]))
1371 metrics = font_info->metrics[block];
1372 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1375 NSRect r = [sfont boundingRectForGlyph: g];
1377 w = max ([sfont advancementForGlyph: g].width, 2.0);
1378 metrics->width = lrint (w);
1381 rb = r.size.width - w;
1382 // Add to bearing for LCD smoothing. We don't know if it is there.
1384 metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1385 if (font_info->ital)
1386 rb += (CGFloat) (0.22F * font_info->height);
1387 metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1389 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1390 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1391 metrics->ascent = r.size.height - metrics->descent;
1392 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1398 #ifdef NS_IMPL_COCOA
1399 /* helper for font glyph setup */
1400 @implementation EmacsGlyphStorage
1404 return [self initWithCapacity: 1024];
1407 - initWithCapacity: (unsigned long) c
1409 self = [super init];
1412 dict = [NSMutableDictionary new];
1413 cglyphs = xmalloc (c * sizeof (CGGlyph));
1426 - (void) setString: (NSString *)str font: (NSFont *)font
1428 [dict setObject: font forKey: NSFontAttributeName];
1431 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1432 maxChar = [str length];
1436 /* NSGlyphStorage protocol */
1437 - (NSUInteger)layoutOptions
1442 - (NSAttributedString *)attributedString
1447 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1448 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1449 characterIndex: (NSUInteger)charIndex
1451 len = glyphIndex+length;
1452 for (i =glyphIndex; i<len; i++)
1453 cglyphs[i] = glyphs[i-glyphIndex];
1458 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1459 forGlyphAtIndex: (NSUInteger)glyphIndex
1465 #endif /* NS_IMPL_COCOA */
1470 ns_dump_glyphstring (struct glyph_string *s)
1474 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1475 "overlap = %d, bg_filled = %d:",
1476 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1477 s->row->overlapping_p, s->background_filled_p);
1478 for (i =0; i<s->nchars; i++)
1480 int c = s->first_glyph[i].u.ch;
1481 fprintf (stderr, "%c", c);
1483 fprintf (stderr, "\n");
1486 struct font_driver const nsfont_driver =
1488 .type = LISPSYM_INITIALLY (Qns),
1489 .case_sensitive = true,
1490 .get_cache = nsfont_get_cache,
1491 .list = nsfont_list,
1492 .match = nsfont_match,
1493 .list_family = nsfont_list_family,
1494 .open = nsfont_open,
1495 .close = nsfont_close,
1496 .has_char = nsfont_has_char,
1497 .encode_char = nsfont_encode_char,
1498 .text_extents = nsfont_text_extents,
1499 .draw = nsfont_draw,
1503 syms_of_nsfont (void)
1505 register_font_driver (&nsfont_driver, NULL);
1506 DEFSYM (Qcondensed, "condensed");
1507 DEFSYM (Qexpanded, "expanded");
1508 DEFSYM (Qapple, "apple");
1509 DEFSYM (Qmedium, "medium");
1510 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1511 doc: /* Internal use: maps font registry to Unicode script. */);
1513 ascii_printable = NULL;