1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX 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 extern float ns_antialias_threshold;
51 /* font glyph and metrics caching functions, implemented at end */
52 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
54 static void ns_glyph_metrics (struct nsfont_info *font_info,
57 #define INVALID_GLYPH 0xFFFF
59 /* ==========================================================================
63 ========================================================================== */
66 /* Replace spaces w/another character so emacs core font parsing routines
69 ns_escape_name (char *name)
77 /* Reconstruct spaces in a font family name passed through emacs. */
79 ns_unescape_name (char *name)
87 /* Extract family name from a font spec. */
89 ns_get_family (Lisp_Object font_spec)
91 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
96 char *tmp = xlispstrdup (SYMBOL_NAME (tem));
98 ns_unescape_name (tmp);
99 family = [NSString stringWithUTF8String: tmp];
106 /* Return 0 if attr not set, else value (which might also be 0).
107 On Leopard 0 gets returned even on descriptors where the attribute
108 was never set, so there's no way to distinguish between unspecified
109 and set to not have. Callers should assume 0 means unspecified. */
111 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
113 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
114 NSNumber *val = [tdict objectForKey: trait];
115 return val == nil ? 0.0F : [val floatValue];
119 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
120 to NSFont descriptor. Information under extra only needed for matching. */
121 #define STYLE_REF 100
122 static NSFontDescriptor *
123 ns_spec_to_descriptor (Lisp_Object font_spec)
125 NSFontDescriptor *fdesc;
126 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
127 NSMutableDictionary *tdict = [NSMutableDictionary new];
128 NSString *family = ns_get_family (font_spec);
131 /* add each attr in font_spec to fdAttrs.. */
132 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
133 if (n != -1 && n != STYLE_REF)
134 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
135 forKey: NSFontWeightTrait];
136 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
137 if (n != -1 && n != STYLE_REF)
138 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
139 forKey: NSFontSlantTrait];
140 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
141 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
142 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
143 forKey: NSFontWidthTrait];
144 if ([tdict count] > 0)
145 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
147 fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
148 retain] autorelease];
152 NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
153 fdesc = [[fdesc2 retain] autorelease];
162 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
164 ns_descriptor_to_entity (NSFontDescriptor *desc,
168 Lisp_Object font_entity = font_make_entity ();
169 /* NSString *psName = [desc postscriptName]; */
170 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
171 unsigned int traits = [desc symbolicTraits];
174 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
176 family = [desc objectForKey: NSFontNameAttribute];
178 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
180 escapedFamily = xstrdup ([family UTF8String]);
181 ns_escape_name (escapedFamily);
183 ASET (font_entity, FONT_TYPE_INDEX, Qns);
184 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
185 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
186 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
187 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
189 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
190 traits & NSFontBoldTrait ? Qbold : Qmedium);
191 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
192 make_number (100 + 100
193 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
194 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
195 traits & NSFontItalicTrait ? Qitalic : Qnormal);
196 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
197 make_number (100 + 100
198 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
199 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
200 traits & NSFontCondensedTrait ? Qcondensed :
201 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
202 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
203 make_number (100 + 100
204 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
206 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
207 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
208 ASET (font_entity, FONT_SPACING_INDEX,
209 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
210 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
212 ASET (font_entity, FONT_EXTRA_INDEX, extra);
213 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
217 fprintf (stderr, "created font_entity:\n ");
218 debug_print (font_entity);
221 xfree (escapedFamily);
226 /* Default font entity. */
228 ns_fallback_entity (void)
230 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
231 fontDescriptor], Qnil, NULL);
235 /* Utility: get width of a char c in screen font SFONT */
237 ns_char_width (NSFont *sfont, int c)
240 NSString *cstr = [NSString stringWithFormat: @"%c", c];
243 NSGlyph glyph = [sfont glyphWithName: cstr];
245 w = [sfont advancementForGlyph: glyph].width;
250 NSDictionary *attrsDictionary =
251 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
252 w = [cstr sizeWithAttributes: attrsDictionary].width;
258 /* Return average width over ASCII printable characters for SFONT. */
260 static NSString *ascii_printable;
263 ns_ascii_average_width (NSFont *sfont)
267 if (!ascii_printable)
271 for (ch = 0; ch < 95; ch++)
272 chars[ch] = ' ' + ch;
275 ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
279 NSGlyph glyph = [sfont glyphWithName: ascii_printable];
281 w = [sfont advancementForGlyph: glyph].width;
284 if (w < (CGFloat) 0.0)
286 NSDictionary *attrsDictionary =
287 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
288 w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
291 return lrint (w / (CGFloat) 95.0);
295 /* Return whether set1 covers set2 to a reasonable extent given by pct.
296 We check, out of each 16 Unicode char range containing chars in set2,
297 whether at least one character is present in set1.
298 This must be true for pct of the pairs to consider it covering. */
300 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
302 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
303 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
304 int i, off = 0, tot = 0;
306 /* Work around what appears to be a GNUstep bug.
307 See <http://bugs.gnu.org/11853>. */
308 if (! (bytes1 && bytes2))
311 for (i=0; i<4096; i++, bytes1++, bytes2++)
315 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
318 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
319 return (float)off / tot < 1.0F - pct;
323 /* Convert :lang property to a script. Use of :lang property by font backend
324 seems to be limited for now (2009/05) to ja, zh, and ko. */
326 *ns_lang_to_script (Lisp_Object lang)
328 if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
330 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
331 have more characters. */
332 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
334 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
341 /* Convert OTF 4-letter script code to emacs script name. (Why can't
342 everyone just use some standard Unicode names for these?) */
344 *ns_otf_to_script (Lisp_Object otf)
346 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
347 return CONSP (script)
348 ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
353 /* Convert a font registry, such as */
355 *ns_registry_to_script (char *reg)
357 Lisp_Object script, r, rts = Vns_reg_to_script;
360 r = XCAR (XCAR (rts));
361 if (!strncmp (SSDATA (r), reg, SBYTES (r)))
363 script = XCDR (XCAR (rts));
364 return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
372 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
373 plus registry regular property, for something that can be mapped to a
374 Unicode script. Empty string returned if no script spec found. */
376 *ns_get_req_script (Lisp_Object font_spec)
378 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
379 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
381 /* The extra-bundle properties have priority. */
382 for ( ; CONSP (extra); extra = XCDR (extra))
384 Lisp_Object tmp = XCAR (extra);
387 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
388 if (EQ (key, QCscript) && SYMBOLP (val))
389 return [NSString stringWithUTF8String:
390 SSDATA (SYMBOL_NAME (val))];
391 if (EQ (key, QClang) && SYMBOLP (val))
392 return ns_lang_to_script (val);
393 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
394 return ns_otf_to_script (val);
398 /* If we get here, check the charset portion of the registry. */
401 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
402 (which causes box rendering if we don't treat it like iso8858-1)
403 but also for ascii (which causes unnecessary font substitution). */
405 if (EQ (reg, Qiso10646_1))
408 return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
415 /* This small function is static in fontset.c. If it can be made public for
416 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
418 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
420 if (EQ (XCAR (arg), val))
423 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
425 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
430 /* Use the Unicode range information in Vchar_script_table to convert a script
431 name into an NSCharacterSet. */
432 static NSCharacterSet
433 *ns_script_to_charset (NSString *scriptName)
435 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
436 Lisp_Object script = intern ([scriptName UTF8String]);
437 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
439 if (! NILP (Fmemq (script, script_list)))
441 Lisp_Object ranges, range_list;
443 ranges = list1 (script);
444 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
446 range_list = Fnreverse (XCDR (ranges));
447 if (! NILP (range_list))
449 for (; CONSP (range_list); range_list = XCDR (range_list))
451 int start = XINT (XCAR (XCAR (range_list)));
452 int end = XINT (XCDR (XCAR (range_list)));
454 debug_print (XCAR (range_list));
456 [charset addCharactersInRange:
457 NSMakeRange (start, end-start)];
465 /* Return an array of font families containing characters for the given
466 script, for the given coverage criterion, including at least LastResort.
467 Results are cached by script for faster access.
468 If none are found, we reduce the percentage and try again, until 5%.
469 This provides a font with at least some characters if such can be found.
470 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
471 (b) need approximate match as fonts covering full Unicode ranges are rare. */
473 *ns_get_covering_families (NSString *script, float pct)
475 static NSMutableDictionary *scriptToFamilies = nil;
476 NSMutableSet *families;
479 NSLog(@"Request covering families for script: '%@'", script);
481 if (scriptToFamilies == nil)
482 scriptToFamilies = [[NSMutableDictionary alloc] init];
484 if ((families = [scriptToFamilies objectForKey: script]) == nil)
486 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
487 NSArray *allFamilies = [fontMgr availableFontFamilies];
489 if ([script length] == 0)
490 families = [NSMutableSet setWithArray: allFamilies];
493 NSCharacterSet *charset = ns_script_to_charset (script);
495 families = [NSMutableSet setWithCapacity: 10];
498 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
499 while ((family = [allFamiliesEnum nextObject]))
501 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
502 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
503 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
505 fset = [NSCharacterSet characterSetWithRange:
506 NSMakeRange (0, 127)];
507 if (ns_charset_covers(fset, charset, pct))
508 [families addObject: family];
511 if ([families count] > 0 || pct < 0.05F)
517 if ([families count] == 0)
518 [families addObject: @"LastResort"];
520 [scriptToFamilies setObject: families forKey: script];
524 NSLog(@" returning %lu families", (unsigned long)[families count]);
529 /* Implementation for list() and match(). List() can return nil, match()
530 must return something. Strategy is to drop family name from attribute
531 matching set for match. */
533 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
535 Lisp_Object tem, list = Qnil;
536 NSFontDescriptor *fdesc, *desc;
538 NSArray *matchingDescs;
547 fprintf (stderr, "nsfont: %s for fontspec:\n ",
548 (isMatch ? "match" : "list"));
549 debug_print (font_spec);
552 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
554 fdesc = ns_spec_to_descriptor (font_spec);
555 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
557 [fkeys removeObject: NSFontFamilyAttribute];
559 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
562 NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
563 (unsigned long)[matchingDescs count]);
565 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
567 if (![cFamilies containsObject:
568 [desc objectForKey: NSFontFamilyAttribute]])
570 tem = ns_descriptor_to_entity (desc,
571 AREF (font_spec, FONT_EXTRA_INDEX),
575 list = Fcons (tem, list);
576 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
580 /* Add synthItal member if needed. */
581 family = [fdesc objectForKey: NSFontFamilyAttribute];
582 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
584 NSFontDescriptor *s1 = [NSFontDescriptor new];
585 NSFontDescriptor *sDesc
586 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
587 fontDescriptorWithFamily: family];
588 list = Fcons (ns_descriptor_to_entity (sDesc,
589 AREF (font_spec, FONT_EXTRA_INDEX),
596 /* Return something if was a match and nothing found. */
598 return ns_fallback_entity ();
601 fprintf (stderr, " Returning %"pI"d entities.\n",
602 XINT (Flength (list)));
609 /* ==========================================================================
611 Font driver implementation
613 ========================================================================== */
616 static Lisp_Object nsfont_get_cache (struct frame *frame);
617 static Lisp_Object nsfont_list (struct frame *, Lisp_Object);
618 static Lisp_Object nsfont_match (struct frame *, Lisp_Object);
619 static Lisp_Object nsfont_list_family (struct frame *);
620 static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity,
622 static void nsfont_close (struct font *font);
623 static int nsfont_has_char (Lisp_Object entity, int c);
624 static unsigned int nsfont_encode_char (struct font *font, int c);
625 static void nsfont_text_extents (struct font *font, unsigned int *code,
626 int nglyphs, struct font_metrics *metrics);
627 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
628 bool with_background);
630 struct font_driver nsfont_driver =
633 1, /* case sensitive */
638 NULL, /*free_entity */
641 NULL, /* prepare_face */
642 NULL, /* done_face */
647 /* excluded: get_bitmap, free_bitmap,
648 anchor_point, otf_capability, otf_driver,
649 start_for_frame, end_for_frame, shape */
653 /* Return a cache of font-entities on FRAME. The cache must be a
654 cons whose cdr part is the actual cache area. */
656 nsfont_get_cache (struct frame *frame)
658 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (frame);
659 return (dpyinfo->name_list_element);
663 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
664 **list** of font-entities. This and match () are sole APIs that allocate
665 font-entities. Properties to be considered (2009/05/19) are:
666 regular: foundry, family, adstyle, registry
667 extended: script, lang, otf
668 "Extended" properties are not part of the vector but get stored as
669 lisp properties under FONT_EXTRA_INDEX.
671 The returned entities should have type set (to 'ns), plus the following:
672 foundry, family, adstyle, registry,
673 weight, slant, width, size (0 if scalable),
674 dpi, spacing, avgwidth (0 if scalable) */
676 nsfont_list (struct frame *f, Lisp_Object font_spec)
678 return ns_findfonts (font_spec, NO);
682 /* Return a font entity most closely matching with FONT_SPEC on
683 FRAME. The closeness is determined by the font backend, thus
684 `face-font-selection-order' is ignored here.
685 Properties to be considered are same as for list(). */
687 nsfont_match (struct frame *f, Lisp_Object font_spec)
689 return ns_findfonts (font_spec, YES);
693 /* List available families. The value is a list of family names
696 nsfont_list_family (struct frame *f)
698 Lisp_Object list = Qnil;
699 NSEnumerator *families;
703 families = [[[NSFontManager sharedFontManager] availableFontFamilies]
705 while ((family = [families nextObject]))
706 list = Fcons (intern ([family UTF8String]), list);
707 /* FIXME: escape the name? */
710 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
711 XINT (Flength (list)));
718 /* Open a font specified by FONT_ENTITY on frame F. If the font is
719 scalable, open it with PIXEL_SIZE. */
721 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
724 unsigned int traits = 0;
725 struct nsfont_info *font_info;
727 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
728 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
730 NSFont *nsfont, *sfont;
733 Lisp_Object font_object;
740 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
741 debug_print (font_entity);
746 /* try to get it out of frame params */
747 Lisp_Object tem = get_frame_param (f, Qfontsize);
748 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
751 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
752 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
754 family = ns_get_family (font_entity);
756 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
757 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
758 when setting family in ns_spec_to_descriptor(). */
759 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
760 traits |= NSBoldFontMask;
761 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
762 traits |= NSItalicFontMask;
764 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
765 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
766 nsfont = [fontMgr fontWithFamily: family
767 traits: traits weight: fixLeopardBug
769 /* if didn't find, try synthetic italic */
770 if (nsfont == nil && synthItal)
772 nsfont = [fontMgr fontWithFamily: family
773 traits: traits & ~NSItalicFontMask
774 weight: fixLeopardBug size: pixel_size];
777 /* LastResort not really a family */
778 if (nsfont == nil && [@"LastResort" isEqualToString: family])
779 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
784 message_with_string ("*** Warning: font in family `%s' not found",
785 build_string ([family UTF8String]), 1);
786 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
790 NSLog (@"%@\n", nsfont);
792 font_object = font_make_object (VECSIZE (struct nsfont_info),
793 font_entity, pixel_size);
794 ASET (font_object, FONT_TYPE_INDEX, nsfont_driver.type);
795 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
796 font = (struct font *) font_info;
800 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
803 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
804 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
808 sfont = [nsfont screenFontWithRenderingMode:
809 NSFontAntialiasedIntegerAdvancementsRenderingMode];
811 sfont = [nsfont screenFont];
817 /* non-metric backend font struct fields */
818 font = (struct font *) font_info;
819 font->pixel_size = [sfont pointSize];
820 font->driver = &nsfont_driver;
821 font->encoding_charset = -1;
822 font->repertory_charset = -1;
823 font->default_ascent = 0;
824 font->vertical_centering = 0;
825 font->baseline_offset = 0;
826 font->relative_compose = 0;
829 const char *fontName = [[nsfont fontName] UTF8String];
831 /* The values specified by fonts are not always exact. For
832 * example, a 6x8 font could specify that the descender is
833 * -2.00000405... (represented by 0xc000000220000000). Without
834 * adjustment, the code below would round the descender to -3,
835 * resulting in a font that would be one pixel higher than
837 CGFloat adjusted_descender = [sfont descender] + 0.0001;
839 #ifdef NS_IMPL_GNUSTEP
840 font_info->nsfont = sfont;
842 font_info->nsfont = nsfont;
844 [font_info->nsfont retain];
846 /* set up ns_font (defined in nsgui.h) */
847 font_info->name = xstrdup (fontName);
848 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
850 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
852 /* Metrics etc.; some fonts return an unusually large max advance, so we
853 only use it for fonts that have wide characters. */
854 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
855 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
857 brect = [sfont boundingRectForFont];
859 font_info->underpos = [sfont underlinePosition];
860 font_info->underwidth = [sfont underlineThickness];
861 font_info->size = font->pixel_size;
864 font->ascent = font_info->max_bounds.ascent = lrint ([sfont ascender]);
865 /* Descender is usually negative. Use floor to avoid
866 clipping descenders. */
868 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
870 font_info->max_bounds.ascent + font_info->max_bounds.descent;
871 font_info->max_bounds.width = lrint (font_info->width);
872 font_info->max_bounds.lbearing = lrint (brect.origin.x);
873 font_info->max_bounds.rbearing =
874 lrint (brect.size.width - (CGFloat) font_info->width);
877 /* set up synthItal and the CG font */
878 font_info->synthItal = synthItal;
880 ATSFontRef atsFont = ATSFontFindFromPostScriptName
881 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
883 if (atsFont == kATSFontRefUnspecified)
885 /* see if we can get it by dropping italic (then synthesizing) */
886 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
887 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
888 fontName], kATSOptionFlagsDefault);
889 if (atsFont != kATSFontRefUnspecified)
890 font_info->synthItal = YES;
893 /* last resort fallback */
894 atsFont = ATSFontFindFromPostScriptName
895 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
898 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
902 /* set up metrics portion of font struct */
903 font->ascent = lrint([sfont ascender]);
904 font->descent = -lrint(floor(adjusted_descender));
905 font->space_width = lrint (ns_char_width (sfont, ' '));
906 font->max_width = lrint (font_info->max_bounds.width);
907 font->min_width = font->space_width; /* Approximate. */
908 font->average_width = ns_ascii_average_width (sfont);
910 font->height = lrint (font_info->height);
911 font->underline_position = lrint (font_info->underpos);
912 font->underline_thickness = lrint (font_info->underwidth);
914 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
915 font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
925 nsfont_close (struct font *font)
927 struct nsfont_info *font_info = (struct nsfont_info *) font;
929 /* FIXME: font_info may be NULL due to same failure to detect
930 same font that causes need for cache in nsfont_open. */
931 if (font_info && font_info->name)
935 for (i = 0; i < 0x100; i++)
937 xfree (font_info->glyphs[i]);
938 xfree (font_info->metrics[i]);
940 xfree (font_info->glyphs);
941 xfree (font_info->metrics);
942 [font_info->nsfont release];
944 CGFontRelease (font_info->cgfont);
946 xfree (font_info->name);
947 font_info->name = NULL;
952 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
953 return 1. If not, return 0. If a font must be opened to check
956 nsfont_has_char (Lisp_Object entity, int c)
962 /* Return a glyph code of FONT for character C (Unicode code point).
963 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
965 nsfont_encode_char (struct font *font, int c)
967 struct nsfont_info *font_info = (struct nsfont_info *)font;
968 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
972 return FONT_INVALID_CODE;
974 /* did we already cache this block? */
975 if (!font_info->glyphs[high])
976 ns_uni_to_glyphs (font_info, high);
978 g = font_info->glyphs[high][low];
979 return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
983 /* Perform the size computation of glyphs of FONT and fill in members
984 of METRICS. The glyphs are specified by their glyph codes in
985 CODE (length NGLYPHS). */
987 nsfont_text_extents (struct font *font, unsigned int *code,
988 int nglyphs, struct font_metrics *metrics)
990 struct nsfont_info *font_info = (struct nsfont_info *)font;
991 struct font_metrics *pcm;
992 unsigned char high, low;
996 memset (metrics, 0, sizeof (struct font_metrics));
998 for (i = 0; i < nglyphs; i++)
1000 /* get metrics for this glyph, filling cache if need be */
1001 /* TODO: get metrics for whole string from an NSLayoutManager
1002 (if not too slow) */
1003 high = (code[i] & 0xFF00) >> 8;
1004 low = code[i] & 0x00FF;
1005 if (!font_info->metrics[high])
1006 ns_glyph_metrics (font_info, high);
1007 pcm = &(font_info->metrics[high][low]);
1009 if (metrics->lbearing > totalWidth + pcm->lbearing)
1010 metrics->lbearing = totalWidth + pcm->lbearing;
1011 if (metrics->rbearing < totalWidth + pcm->rbearing)
1012 metrics->rbearing = totalWidth + pcm->rbearing;
1013 if (metrics->ascent < pcm->ascent)
1014 metrics->ascent = pcm->ascent;
1015 if (metrics->descent < pcm->descent)
1016 metrics->descent = pcm->descent;
1018 totalWidth += pcm->width;
1021 metrics->width = totalWidth;
1025 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1026 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1027 fill the background in advance. It is assured that WITH_BACKGROUND
1028 is false when (FROM > 0 || TO < S->nchars). */
1030 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1031 bool with_background)
1032 /* NOTE: focus and clip must be set */
1034 static unsigned char cbuf[1024];
1035 unsigned char *c = cbuf;
1036 #ifdef NS_IMPL_GNUSTEP
1037 #if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22
1038 static CGFloat advances[1024];
1039 CGFloat *adv = advances;
1041 static float advances[1024];
1042 float *adv = advances;
1045 static CGSize advances[1024];
1046 CGSize *adv = advances;
1050 struct nsfont_info *font;
1051 NSColor *col, *bgCol;
1052 unsigned short *t = s->char2b;
1054 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1058 font = (struct nsfont_info *)s->face->font;
1060 font = (struct nsfont_info *)FRAME_FONT (s->f);
1062 /* Select face based on input flags */
1063 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
1064 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
1065 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
1066 NS_DUMPGLYPH_NORMAL));
1070 case NS_DUMPGLYPH_CURSOR:
1073 case NS_DUMPGLYPH_MOUSEFACE:
1074 face = FACE_FROM_ID_OR_NULL (s->f,
1075 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1077 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1084 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1085 r.origin.x += abs (s->face->box_line_width);
1088 r.size.height = FONT_HEIGHT (font);
1090 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1091 NS to render the string, it will come out differently from the individual
1092 character widths added up because of layout processing. */
1094 int cwidth, twidth = 0;
1096 /* FIXME: composition: no vertical displacement is considered. */
1097 t += from; /* advance into composition */
1098 for (i = from; i < to; i++, t++)
1100 hi = (*t & 0xFF00) >> 8;
1104 if (!s->first_glyph->u.cmp.automatic)
1105 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1108 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1109 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1110 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1111 cwidth = LGLYPH_WIDTH (glyph);
1114 cwidth = LGLYPH_WADJUST (glyph);
1115 #ifdef NS_IMPL_GNUSTEP
1116 *(adv-1) += LGLYPH_XOFF (glyph);
1118 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1125 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1126 ns_glyph_metrics (font, hi);
1127 cwidth = font->metrics[hi][lo].width;
1130 #ifdef NS_IMPL_GNUSTEP
1132 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1134 (*adv++).width = cwidth;
1137 len = adv - advances;
1138 r.size.width = twidth;
1142 /* fill background if requested */
1143 if (with_background && !isComposite)
1146 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1147 int mbox_line_width = max (s->face->box_line_width, 0);
1149 if (s->row->full_width_p)
1151 if (br.origin.x <= fibw + 1 + mbox_line_width)
1153 br.size.width += br.origin.x - mbox_line_width;
1154 br.origin.x = mbox_line_width;
1156 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1158 br.size.width += fibw;
1160 if (s->face->box == FACE_NO_BOX)
1162 /* expand unboxed top row over internal border */
1163 if (br.origin.y <= fibw + 1 + mbox_line_width)
1165 br.size.height += br.origin.y;
1171 int correction = abs (s->face->box_line_width)+1;
1172 br.origin.y += correction;
1173 br.size.height -= 2*correction;
1174 br.origin.x += correction;
1175 br.size.width -= 2*correction;
1178 if (!s->face->stipple)
1179 [(NS_FACE_BACKGROUND (face) != 0
1180 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1181 : FRAME_BACKGROUND_COLOR (s->f)) set];
1184 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
1185 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1191 /* set up for character rendering */
1194 col = (NS_FACE_FOREGROUND (face) != 0
1195 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1196 : FRAME_FOREGROUND_COLOR (s->f));
1198 bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
1199 : (NS_FACE_BACKGROUND (face) != 0
1200 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1201 : FRAME_BACKGROUND_COLOR (s->f)));
1203 /* render under GNUstep using DPS */
1204 #ifdef NS_IMPL_GNUSTEP
1206 NSGraphicsContext *context = GSCurrentContext ();
1211 /* do erase if "foreground" mode */
1215 DPSmoveto (context, r.origin.x, r.origin.y);
1216 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1217 DPSxshow (context, (const char *) cbuf, advances, len);
1218 DPSstroke (context);
1220 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1225 /* draw with DPSxshow () */
1226 DPSmoveto (context, r.origin.x, r.origin.y);
1227 DPSxshow (context, (const char *) cbuf, advances, len);
1228 DPSstroke (context);
1230 DPSgrestore (context);
1233 #else /* NS_IMPL_COCOA */
1235 CGContextRef gcontext =
1236 [[NSGraphicsContext currentContext] graphicsPort];
1237 static CGAffineTransform fliptf;
1238 static BOOL firstTime = YES;
1243 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1246 CGContextSaveGState (gcontext);
1248 // Used to be Fix2X (kATSItalicQDSkew), but Fix2X is deprecated
1249 // and kATSItalicQDSkew is 0.25.
1250 fliptf.c = font->synthItal ? 0.25 : 0.0;
1252 CGContextSetFont (gcontext, font->cgfont);
1253 CGContextSetFontSize (gcontext, font->size);
1254 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1255 CGContextSetShouldAntialias (gcontext, 0);
1257 CGContextSetShouldAntialias (gcontext, 1);
1259 CGContextSetTextMatrix (gcontext, fliptf);
1263 /* foreground drawing; erase first to avoid overstrike */
1265 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1266 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1267 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1268 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1273 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1274 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1277 if (face->overstrike)
1279 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1280 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1284 CGContextRestoreGState (gcontext);
1286 #endif /* NS_IMPL_COCOA */
1294 /* ==========================================================================
1296 Font glyph and metrics caching functions
1298 ========================================================================== */
1300 /* Find and cache corresponding glyph codes for unicode values in given
1301 hi-byte block of 256. */
1303 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1305 #ifdef NS_IMPL_COCOA
1306 static EmacsGlyphStorage *glyphStorage;
1307 static char firstTime = 1;
1309 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1310 unsigned int i, g, idx;
1311 unsigned short *glyphs;
1314 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1319 #ifdef NS_IMPL_COCOA
1323 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1327 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1328 if (!unichars || !(font_info->glyphs[block]))
1331 /* create a string containing all Unicode characters in this block */
1332 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1333 if (idx < 0xD800 || idx > 0xDFFF)
1336 unichars[i] = 0xFEFF;
1337 unichars[0x100] = 0;
1340 #ifdef NS_IMPL_COCOA
1341 NSString *allChars = [[NSString alloc]
1342 initWithCharactersNoCopy: unichars
1345 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1346 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1347 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1348 NSUInteger gInd = 0, cInd = 0;
1350 [glyphStorage setString: allChars font: font_info->nsfont];
1351 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1352 desiredNumberOfCharacters: glyphStorage->maxChar
1353 glyphIndex: &gInd characterIndex: &cInd];
1355 glyphs = font_info->glyphs[block];
1356 for (i = 0; i < 0x100; i++, glyphs++)
1358 #ifdef NS_IMPL_GNUSTEP
1361 g = glyphStorage->cglyphs[i];
1362 /* TODO: is this a good check? maybe need to use coveredChars.. */
1363 if (g > numGlyphs || g == NSNullGlyph)
1364 g = INVALID_GLYPH; /* hopefully unused... */
1369 #ifdef NS_IMPL_COCOA
1379 /* Determine and cache metrics for corresponding glyph codes in given
1380 hi-byte block of 256. */
1382 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1385 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1387 struct font_metrics *metrics;
1390 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1393 #ifdef NS_IMPL_GNUSTEP
1394 /* not implemented yet (as of startup 0.18), so punt */
1396 numGlyphs = 0x10000;
1400 #ifdef NS_IMPL_COCOA
1401 sfont = [font_info->nsfont screenFontWithRenderingMode:
1402 NSFontAntialiasedIntegerAdvancementsRenderingMode];
1404 sfont = [font_info->nsfont screenFont];
1407 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1408 if (!(font_info->metrics[block]))
1411 metrics = font_info->metrics[block];
1412 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1415 NSRect r = [sfont boundingRectForGlyph: g];
1417 w = max ([sfont advancementForGlyph: g].width, 2.0);
1418 metrics->width = lrint (w);
1421 rb = r.size.width - w;
1422 // Add to bearing for LCD smoothing. We don't know if it is there.
1424 metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1425 if (font_info->ital)
1426 rb += (CGFloat) (0.22F * font_info->height);
1427 metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1429 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1430 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1431 metrics->ascent = r.size.height - metrics->descent;
1432 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1438 #ifdef NS_IMPL_COCOA
1439 /* helper for font glyph setup */
1440 @implementation EmacsGlyphStorage
1444 return [self initWithCapacity: 1024];
1447 - initWithCapacity: (unsigned long) c
1449 self = [super init];
1452 dict = [NSMutableDictionary new];
1453 cglyphs = xmalloc (c * sizeof (CGGlyph));
1466 - (void) setString: (NSString *)str font: (NSFont *)font
1468 [dict setObject: font forKey: NSFontAttributeName];
1471 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1472 maxChar = [str length];
1476 /* NSGlyphStorage protocol */
1477 - (NSUInteger)layoutOptions
1482 - (NSAttributedString *)attributedString
1487 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1488 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1489 characterIndex: (NSUInteger)charIndex
1491 len = glyphIndex+length;
1492 for (i =glyphIndex; i<len; i++)
1493 cglyphs[i] = glyphs[i-glyphIndex];
1498 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1499 forGlyphAtIndex: (NSUInteger)glyphIndex
1505 #endif /* NS_IMPL_COCOA */
1510 ns_dump_glyphstring (struct glyph_string *s)
1514 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1515 "overlap = %d, bg_filled = %d:",
1516 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1517 s->row->overlapping_p, s->background_filled_p);
1518 for (i =0; i<s->nchars; i++)
1519 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
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;