1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006-2013 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
23 /* This should be the first include, as it may set up #defines affecting
24 interpretation of even the system includes. */
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
36 #include "character.h"
40 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
41 #ifdef NS_IMPL_GNUSTEP
42 #import <AppKit/NSFontDescriptor.h>
45 #define NSFONT_TRACE 0
46 #define LCD_SMOOTHING_MARGIN 2
48 extern Lisp_Object Qns;
49 extern Lisp_Object Qnormal, Qbold, Qitalic;
50 static Lisp_Object Qapple, Qroman, Qmedium;
51 static Lisp_Object Qcondensed, Qexpanded;
52 extern Lisp_Object Qappend;
53 extern float ns_antialias_threshold;
54 extern int ns_tmp_flags;
55 extern struct nsfont_info *ns_tmp_font;
58 /* font glyph and metrics caching functions, implemented at end */
59 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
61 static void ns_glyph_metrics (struct nsfont_info *font_info,
64 #define INVALID_GLYPH 0xFFFF
66 /* ==========================================================================
70 ========================================================================== */
73 /* Replace spaces w/another character so emacs core font parsing routines
76 ns_escape_name (char *name)
84 /* Reconstruct spaces in a font family name passed through emacs. */
86 ns_unescape_name (char *name)
94 /* Extract family name from a font spec. */
96 ns_get_family (Lisp_Object font_spec)
98 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
103 char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
105 ns_unescape_name (tmp);
106 family = [NSString stringWithUTF8String: tmp];
113 /* Return 0 if attr not set, else value (which might also be 0).
114 On Leopard 0 gets returned even on descriptors where the attribute
115 was never set, so there's no way to distinguish between unspecified
116 and set to not have. Callers should assume 0 means unspecified. */
118 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
120 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
121 NSNumber *val = [tdict objectForKey: trait];
122 return val == nil ? 0.0F : [val floatValue];
126 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
127 to NSFont descriptor. Information under extra only needed for matching. */
128 #define STYLE_REF 100
129 static NSFontDescriptor *
130 ns_spec_to_descriptor (Lisp_Object font_spec)
132 NSFontDescriptor *fdesc;
133 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
134 NSMutableDictionary *tdict = [NSMutableDictionary new];
135 NSString *family = ns_get_family (font_spec);
138 /* add each attr in font_spec to fdAttrs.. */
139 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
140 if (n != -1 && n != STYLE_REF)
141 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
142 forKey: NSFontWeightTrait];
143 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
144 if (n != -1 && n != STYLE_REF)
145 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
146 forKey: NSFontSlantTrait];
147 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
148 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
149 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
150 forKey: NSFontWidthTrait];
151 if ([tdict count] > 0)
152 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
154 fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
155 retain] autorelease];
159 NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
160 fdesc = [[fdesc2 retain] autorelease];
169 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
171 ns_descriptor_to_entity (NSFontDescriptor *desc,
175 Lisp_Object font_entity = font_make_entity ();
176 /* NSString *psName = [desc postscriptName]; */
177 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
178 unsigned int traits = [desc symbolicTraits];
181 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
183 family = [desc objectForKey: NSFontNameAttribute];
185 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
187 escapedFamily = xstrdup ([family UTF8String]);
188 ns_escape_name (escapedFamily);
190 ASET (font_entity, FONT_TYPE_INDEX, Qns);
191 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
192 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
193 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
194 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
196 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
197 traits & NSFontBoldTrait ? Qbold : Qmedium);
198 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
199 make_number (100 + 100
200 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
201 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
202 traits & NSFontItalicTrait ? Qitalic : Qnormal);
203 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
204 make_number (100 + 100
205 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
206 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
207 traits & NSFontCondensedTrait ? Qcondensed :
208 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
209 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
210 make_number (100 + 100
211 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
213 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
214 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
215 ASET (font_entity, FONT_SPACING_INDEX,
216 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
217 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
219 ASET (font_entity, FONT_EXTRA_INDEX, extra);
220 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
224 fprintf (stderr, "created font_entity:\n ");
225 debug_print (font_entity);
228 xfree (escapedFamily);
233 /* Default font entity. */
235 ns_fallback_entity (void)
237 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
238 fontDescriptor], Qnil, NULL);
242 /* Utility: get width of a char c in screen font SFONT */
244 ns_char_width (NSFont *sfont, int c)
247 NSString *cstr = [NSString stringWithFormat: @"%c", c];
250 NSGlyph glyph = [sfont glyphWithName: cstr];
252 w = [sfont advancementForGlyph: glyph].width;
257 NSDictionary *attrsDictionary =
258 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
259 w = [cstr sizeWithAttributes: attrsDictionary].width;
265 /* Return average width over ASCII printable characters for SFONT. */
267 static NSString *ascii_printable;
270 ns_ascii_average_width (NSFont *sfont)
274 if (!ascii_printable)
278 for (ch = 0; ch < 95; ch++)
279 chars[ch] = ' ' + ch;
282 ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
286 NSGlyph glyph = [sfont glyphWithName: ascii_printable];
288 w = [sfont advancementForGlyph: glyph].width;
291 if (w < (CGFloat) 0.0)
293 NSDictionary *attrsDictionary =
294 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
295 w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
298 return lrint (w / (CGFloat) 95.0);
302 /* Return whether set1 covers set2 to a reasonable extent given by pct.
303 We check, out of each 16 Unicode char range containing chars in set2,
304 whether at least one character is present in set1.
305 This must be true for pct of the pairs to consider it covering. */
307 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
309 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
310 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
311 int i, off = 0, tot = 0;
313 /* Work around what appears to be a GNUstep bug.
314 See <http://bugs.gnu.org/11853>. */
315 if (! (bytes1 && bytes2))
318 for (i=0; i<4096; i++, bytes1++, bytes2++)
322 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
325 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
326 return (float)off / tot < 1.0F - pct;
330 /* Convert :lang property to a script. Use of :lang property by font backend
331 seems to be limited for now (2009/05) to ja, zh, and ko. */
333 *ns_lang_to_script (Lisp_Object lang)
335 if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
337 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
338 have more characters. */
339 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
341 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
348 /* Convert OTF 4-letter script code to emacs script name. (Why can't
349 everyone just use some standard Unicode names for these?) */
351 *ns_otf_to_script (Lisp_Object otf)
353 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
354 return CONSP (script)
355 ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
360 /* Convert a font registry, such as */
362 *ns_registry_to_script (char *reg)
364 Lisp_Object script, r, rts = Vns_reg_to_script;
367 r = XCAR (XCAR (rts));
368 if (!strncmp (SSDATA (r), reg, SBYTES (r)))
370 script = XCDR (XCAR (rts));
371 return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
379 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
380 plus registry regular property, for something that can be mapped to a
381 Unicode script. Empty string returned if no script spec found. */
383 *ns_get_req_script (Lisp_Object font_spec)
385 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
386 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
388 /* The extra-bundle properties have priority. */
389 for ( ; CONSP (extra); extra = XCDR (extra))
391 Lisp_Object tmp = XCAR (extra);
394 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
395 if (EQ (key, QCscript) && SYMBOLP (val))
396 return [NSString stringWithUTF8String:
397 SSDATA (SYMBOL_NAME (val))];
398 if (EQ (key, QClang) && SYMBOLP (val))
399 return ns_lang_to_script (val);
400 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
401 return ns_otf_to_script (val);
405 /* If we get here, check the charset portion of the registry. */
408 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
409 (which causes box rendering if we don't treat it like iso8858-1)
410 but also for ascii (which causes unnecessary font substitution). */
412 if (EQ (reg, Qiso10646_1))
415 return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
422 /* This small function is static in fontset.c. If it can be made public for
423 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
425 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
427 if (EQ (XCAR (arg), val))
430 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
432 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
437 /* Use the Unicode range information in Vchar_script_table to convert a script
438 name into an NSCharacterSet. */
439 static NSCharacterSet
440 *ns_script_to_charset (NSString *scriptName)
442 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
443 Lisp_Object script = intern ([scriptName UTF8String]);
444 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
446 if (! NILP (Fmemq (script, script_list)))
448 Lisp_Object ranges, range_list;
450 ranges = list1 (script);
451 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
453 range_list = Fnreverse (XCDR (ranges));
454 if (! NILP (range_list))
456 for (; CONSP (range_list); range_list = XCDR (range_list))
458 int start = XINT (XCAR (XCAR (range_list)));
459 int end = XINT (XCDR (XCAR (range_list)));
461 debug_print (XCAR (range_list));
463 [charset addCharactersInRange:
464 NSMakeRange (start, end-start)];
472 /* Return an array of font families containing characters for the given
473 script, for the given coverage criterion, including at least LastResort.
474 Results are cached by script for faster access.
475 If none are found, we reduce the percentage and try again, until 5%.
476 This provides a font with at least some characters if such can be found.
477 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
478 (b) need approximate match as fonts covering full Unicode ranges are rare. */
480 *ns_get_covering_families (NSString *script, float pct)
482 static NSMutableDictionary *scriptToFamilies = nil;
483 NSMutableSet *families;
486 NSLog(@"Request covering families for script: '%@'", script);
488 if (scriptToFamilies == nil)
489 scriptToFamilies = [[NSMutableDictionary alloc] init];
491 if ((families = [scriptToFamilies objectForKey: script]) == nil)
493 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
494 NSArray *allFamilies = [fontMgr availableFontFamilies];
496 if ([script length] == 0)
497 families = [NSMutableSet setWithArray: allFamilies];
500 NSCharacterSet *charset = ns_script_to_charset (script);
502 families = [NSMutableSet setWithCapacity: 10];
505 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
506 while ((family = [allFamiliesEnum nextObject]))
508 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
509 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
510 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
512 fset = [NSCharacterSet characterSetWithRange:
513 NSMakeRange (0, 127)];
514 if (ns_charset_covers(fset, charset, pct))
515 [families addObject: family];
518 if ([families count] > 0 || pct < 0.05F)
524 if ([families count] == 0)
525 [families addObject: @"LastResort"];
527 [scriptToFamilies setObject: families forKey: script];
531 NSLog(@" returning %d families", [families count]);
536 /* Implementation for list() and match(). List() can return nil, match()
537 must return something. Strategy is to drop family name from attribute
538 matching set for match. */
540 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
542 Lisp_Object tem, list = Qnil;
543 NSFontDescriptor *fdesc, *desc;
545 NSArray *matchingDescs;
554 fprintf (stderr, "nsfont: %s for fontspec:\n ",
555 (isMatch ? "match" : "list"));
556 debug_print (font_spec);
559 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
561 fdesc = ns_spec_to_descriptor (font_spec);
562 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
564 [fkeys removeObject: NSFontFamilyAttribute];
566 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
569 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
570 [matchingDescs count]);
572 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
574 if (![cFamilies containsObject:
575 [desc objectForKey: NSFontFamilyAttribute]])
577 tem = ns_descriptor_to_entity (desc,
578 AREF (font_spec, FONT_EXTRA_INDEX),
582 list = Fcons (tem, list);
583 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
587 /* Add synthItal member if needed. */
588 family = [fdesc objectForKey: NSFontFamilyAttribute];
589 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
591 NSFontDescriptor *s1 = [NSFontDescriptor new];
592 NSFontDescriptor *sDesc
593 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
594 fontDescriptorWithFamily: family];
595 list = Fcons (ns_descriptor_to_entity (sDesc,
596 AREF (font_spec, FONT_EXTRA_INDEX),
603 /* Return something if was a match and nothing found. */
605 return ns_fallback_entity ();
608 fprintf (stderr, " Returning %"pI"d entities.\n",
609 XINT (Flength (list)));
616 /* ==========================================================================
618 Font driver implementation
620 ========================================================================== */
623 static Lisp_Object nsfont_get_cache (struct frame *frame);
624 static Lisp_Object nsfont_list (struct frame *, Lisp_Object);
625 static Lisp_Object nsfont_match (struct frame *, Lisp_Object);
626 static Lisp_Object nsfont_list_family (struct frame *);
627 static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity,
629 static void nsfont_close (struct frame *f, struct font *font);
630 static int nsfont_has_char (Lisp_Object entity, int c);
631 static unsigned int nsfont_encode_char (struct font *font, int c);
632 static int nsfont_text_extents (struct font *font, unsigned int *code,
633 int nglyphs, struct font_metrics *metrics);
634 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
635 bool with_background);
637 struct font_driver nsfont_driver =
640 1, /* case sensitive */
645 NULL, /*free_entity */
648 NULL, /* prepare_face */
649 NULL, /* done_face */
654 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
655 anchor_point, otf_capability, otf_driver,
656 start_for_frame, end_for_frame, shape */
660 /* Return a cache of font-entities on FRAME. The cache must be a
661 cons whose cdr part is the actual cache area. */
663 nsfont_get_cache (struct frame *frame)
665 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
666 return (dpyinfo->name_list_element);
670 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
671 **list** of font-entities. This and match () are sole APIs that allocate
672 font-entities. Properties to be considered (2009/05/19) are:
673 regular: foundry, family, adstyle, registry
674 extended: script, lang, otf
675 "Extended" properties are not part of the vector but get stored as
676 lisp properties under FONT_EXTRA_INDEX.
678 The returned entities should have type set (to 'ns), plus the following:
679 foundry, family, adstyle, registry,
680 weight, slant, width, size (0 if scalable),
681 dpi, spacing, avgwidth (0 if scalable) */
683 nsfont_list (struct frame *f, Lisp_Object font_spec)
685 return ns_findfonts (font_spec, NO);
689 /* Return a font entity most closely matching with FONT_SPEC on
690 FRAME. The closeness is determined by the font backend, thus
691 `face-font-selection-order' is ignored here.
692 Properties to be considered are same as for list(). */
694 nsfont_match (struct frame *f, Lisp_Object font_spec)
696 return ns_findfonts (font_spec, YES);
700 /* List available families. The value is a list of family names
703 nsfont_list_family (struct frame *f)
705 Lisp_Object list = Qnil;
706 NSEnumerator *families;
710 families = [[[NSFontManager sharedFontManager] availableFontFamilies]
712 while ((family = [families nextObject]))
713 list = Fcons (intern ([family UTF8String]), list);
714 /* FIXME: escape the name? */
717 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
718 XINT (Flength (list)));
725 /* Open a font specified by FONT_ENTITY on frame F. If the font is
726 scalable, open it with PIXEL_SIZE. */
728 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
731 unsigned int traits = 0;
732 struct nsfont_info *font_info;
734 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
735 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
737 NSFont *nsfont, *sfont;
740 Lisp_Object font_object;
747 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
748 debug_print (font_entity);
753 /* try to get it out of frame params */
754 Lisp_Object tem = get_frame_param (f, Qfontsize);
755 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
758 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
759 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
761 family = ns_get_family (font_entity);
763 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
764 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
765 when setting family in ns_spec_to_descriptor(). */
766 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
767 traits |= NSBoldFontMask;
768 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
769 traits |= NSItalicFontMask;
771 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
772 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
773 nsfont = [fontMgr fontWithFamily: family
774 traits: traits weight: fixLeopardBug
776 /* if didn't find, try synthetic italic */
777 if (nsfont == nil && synthItal)
779 nsfont = [fontMgr fontWithFamily: family
780 traits: traits & ~NSItalicFontMask
781 weight: fixLeopardBug size: pixel_size];
784 /* LastResort not really a family */
785 if (nsfont == nil && [@"LastResort" isEqualToString: family])
786 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
791 message_with_string ("*** Warning: font in family '%s' not found",
792 build_string ([family UTF8String]), 1);
793 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
797 NSLog (@"%@\n", nsfont);
799 font_object = font_make_object (VECSIZE (struct nsfont_info),
800 font_entity, pixel_size);
801 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
802 font = (struct font *) font_info;
806 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
809 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
810 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
814 sfont = [nsfont screenFontWithRenderingMode:
815 NSFontAntialiasedIntegerAdvancementsRenderingMode];
817 sfont = [nsfont screenFont];
823 /* non-metric backend font struct fields */
824 font = (struct font *) font_info;
825 font->pixel_size = [sfont pointSize];
826 font->driver = &nsfont_driver;
827 font->encoding_charset = -1;
828 font->repertory_charset = -1;
829 font->default_ascent = 0;
830 font->vertical_centering = 0;
831 font->baseline_offset = 0;
832 font->relative_compose = 0;
833 font->font_encoder = NULL;
835 font->props[FONT_FORMAT_INDEX] = Qns;
836 font->props[FONT_FILE_INDEX] = Qnil;
839 const char *fontName = [[nsfont fontName] UTF8String];
841 /* The values specified by fonts are not always exact. For
842 * example, a 6x8 font could specify that the descender is
843 * -2.00000405... (represented by 0xc000000220000000). Without
844 * adjustment, the code below would round the descender to -3,
845 * resulting in a font that would be one pixel higher than
847 CGFloat adjusted_descender = [sfont descender] + 0.0001;
849 #ifdef NS_IMPL_GNUSTEP
850 font_info->nsfont = sfont;
852 font_info->nsfont = nsfont;
854 [font_info->nsfont retain];
856 /* set up ns_font (defined in nsgui.h) */
857 font_info->name = xstrdup (fontName);
858 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
860 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
862 /* Metrics etc.; some fonts return an unusually large max advance, so we
863 only use it for fonts that have wide characters. */
864 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
865 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
867 brect = [sfont boundingRectForFont];
869 font_info->underpos = [sfont underlinePosition];
870 font_info->underwidth = [sfont underlineThickness];
871 font_info->size = font->pixel_size;
874 font_info->max_bounds.ascent = lrint ([sfont ascender]);
875 /* Descender is usually negative. Use floor to avoid
876 clipping descenders. */
877 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
879 font_info->max_bounds.ascent + font_info->max_bounds.descent;
880 font_info->max_bounds.width = lrint (font_info->width);
881 font_info->max_bounds.lbearing = lrint (brect.origin.x);
882 font_info->max_bounds.rbearing =
883 lrint (brect.size.width - (CGFloat) font_info->width);
886 /* set up synthItal and the CG font */
887 font_info->synthItal = synthItal;
889 ATSFontRef atsFont = ATSFontFindFromPostScriptName
890 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
892 if (atsFont == kATSFontRefUnspecified)
894 /* see if we can get it by dropping italic (then synthesizing) */
895 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
896 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
897 fontName], kATSOptionFlagsDefault);
898 if (atsFont != kATSFontRefUnspecified)
899 font_info->synthItal = YES;
902 /* last resort fallback */
903 atsFont = ATSFontFindFromPostScriptName
904 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
907 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
911 /* set up metrics portion of font struct */
912 font->ascent = lrint([sfont ascender]);
913 font->descent = -lrint(floor(adjusted_descender));
914 font->space_width = lrint (ns_char_width (sfont, ' '));
915 font->max_width = lrint (font_info->max_bounds.width);
916 font->min_width = font->space_width; /* Approximate. */
917 font->average_width = ns_ascii_average_width (sfont);
919 font->height = lrint (font_info->height);
920 font->underline_position = lrint (font_info->underpos);
921 font->underline_thickness = lrint (font_info->underwidth);
923 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
924 font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
932 /* Close FONT on frame F. */
934 nsfont_close (struct frame *f, struct font *font)
936 struct nsfont_info *font_info = (struct nsfont_info *)font;
939 /* FIXME: this occurs apparently due to same failure to detect same font
940 that causes need for cache in nsfont_open () */
944 for (i =0; i<0x100; i++)
946 xfree (font_info->glyphs[i]);
947 xfree (font_info->metrics[i]);
949 [font_info->nsfont release];
951 CGFontRelease (font_info->cgfont);
953 xfree (font_info->name);
958 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
959 return 1. If not, return 0. If a font must be opened to check
962 nsfont_has_char (Lisp_Object entity, int c)
968 /* Return a glyph code of FONT for character C (Unicode code point).
969 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
971 nsfont_encode_char (struct font *font, int c)
973 struct nsfont_info *font_info = (struct nsfont_info *)font;
974 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
978 return FONT_INVALID_CODE;
980 /* did we already cache this block? */
981 if (!font_info->glyphs[high])
982 ns_uni_to_glyphs (font_info, high);
984 g = font_info->glyphs[high][low];
985 return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
989 /* Perform the size computation of glyphs of FONT and fill in members
990 of METRICS. The glyphs are specified by their glyph codes in
991 CODE (length NGLYPHS). */
993 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
994 struct font_metrics *metrics)
996 struct nsfont_info *font_info = (struct nsfont_info *)font;
997 struct font_metrics *pcm;
998 unsigned char high, low;
1002 memset (metrics, 0, sizeof (struct font_metrics));
1004 for (i =0; i<nglyphs; i++)
1006 /* get metrics for this glyph, filling cache if need be */
1007 /* TODO: get metrics for whole string from an NSLayoutManager
1008 (if not too slow) */
1009 high = (code[i] & 0xFF00) >> 8;
1010 low = code[i] & 0x00FF;
1011 if (!font_info->metrics[high])
1012 ns_glyph_metrics (font_info, high);
1013 pcm = &(font_info->metrics[high][low]);
1015 if (metrics->lbearing > totalWidth + pcm->lbearing)
1016 metrics->lbearing = totalWidth + pcm->lbearing;
1017 if (metrics->rbearing < totalWidth + pcm->rbearing)
1018 metrics->rbearing = totalWidth + pcm->rbearing;
1019 if (metrics->ascent < pcm->ascent)
1020 metrics->ascent = pcm->ascent;
1021 if (metrics->descent < pcm->descent)
1022 metrics->descent = pcm->descent;
1024 totalWidth += pcm->width;
1027 metrics->width = totalWidth;
1029 return totalWidth; /* not specified in doc, but xfont.c does it */
1033 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1034 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1035 fill the background in advance. It is assured that WITH_BACKGROUND
1036 is false when (FROM > 0 || TO < S->nchars). */
1038 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1039 bool with_background)
1040 /* NOTE: focus and clip must be set
1041 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1043 static unsigned char cbuf[1024];
1044 unsigned char *c = cbuf;
1045 #ifdef NS_IMPL_GNUSTEP
1046 static float advances[1024];
1047 float *adv = advances;
1049 static CGSize advances[1024];
1050 CGSize *adv = advances;
1054 struct nsfont_info *font = ns_tmp_font;
1055 NSColor *col, *bgCol;
1056 unsigned short *t = s->char2b;
1058 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1059 int end = isComposite ? s->cmp_to : s->nchars;
1062 /* Select face based on input flags */
1063 switch (ns_tmp_flags)
1065 case NS_DUMPGLYPH_CURSOR:
1068 case NS_DUMPGLYPH_MOUSEFACE:
1069 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1071 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1078 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1079 r.origin.x += abs (s->face->box_line_width);
1082 r.size.height = FONT_HEIGHT (font);
1084 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1085 NS to render the string, it will come out differently from the individual
1086 character widths added up because of layout processing. */
1088 int cwidth, twidth = 0;
1090 /* FIXME: composition: no vertical displacement is considered. */
1091 t += s->cmp_from; /* advance into composition */
1092 for (i = s->cmp_from; i < end; i++, t++)
1094 hi = (*t & 0xFF00) >> 8;
1098 if (!s->first_glyph->u.cmp.automatic)
1099 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1102 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1103 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1104 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1105 cwidth = LGLYPH_WIDTH (glyph);
1108 cwidth = LGLYPH_WADJUST (glyph);
1109 #ifdef NS_IMPL_GNUSTEP
1110 *(adv-1) += LGLYPH_XOFF (glyph);
1112 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1119 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1120 ns_glyph_metrics (font, hi);
1121 cwidth = font->metrics[hi][lo].width;
1124 #ifdef NS_IMPL_GNUSTEP
1126 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1128 (*adv++).width = cwidth;
1131 len = adv - advances;
1132 r.size.width = twidth;
1136 /* fill background if requested */
1137 if (with_background && !isComposite)
1140 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1141 int mbox_line_width = max (s->face->box_line_width, 0);
1143 if (s->row->full_width_p)
1145 if (br.origin.x <= fibw + 1 + mbox_line_width)
1147 br.size.width += br.origin.x - mbox_line_width;
1148 br.origin.x = mbox_line_width;
1150 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1152 br.size.width += fibw;
1154 if (s->face->box == FACE_NO_BOX)
1156 /* expand unboxed top row over internal border */
1157 if (br.origin.y <= fibw + 1 + mbox_line_width)
1159 br.size.height += br.origin.y;
1165 int correction = abs (s->face->box_line_width)+1;
1166 br.origin.y += correction;
1167 br.size.height -= 2*correction;
1168 br.origin.x += correction;
1169 br.size.width -= 2*correction;
1172 if (!s->face->stipple)
1173 [(NS_FACE_BACKGROUND (face) != 0
1174 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1175 : FRAME_BACKGROUND_COLOR (s->f)) set];
1178 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1179 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1185 /* set up for character rendering */
1186 r.origin.y = s->ybase;
1188 col = (NS_FACE_FOREGROUND (face) != 0
1189 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1190 : FRAME_FOREGROUND_COLOR (s->f));
1191 /* FIXME: find another way to pass this */
1192 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1193 : (NS_FACE_BACKGROUND (face) != 0
1194 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1195 : FRAME_BACKGROUND_COLOR (s->f)));
1197 /* render under GNUstep using DPS */
1198 #ifdef NS_IMPL_GNUSTEP
1200 NSGraphicsContext *context = GSCurrentContext ();
1205 /* do erase if "foreground" mode */
1209 DPSmoveto (context, r.origin.x, r.origin.y);
1210 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1211 DPSxshow (context, (const char *) cbuf, advances, len);
1212 DPSstroke (context);
1214 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1219 /* draw with DPSxshow () */
1220 DPSmoveto (context, r.origin.x, r.origin.y);
1221 DPSxshow (context, (const char *) cbuf, advances, len);
1222 DPSstroke (context);
1224 DPSgrestore (context);
1227 #else /* NS_IMPL_COCOA */
1229 CGContextRef gcontext =
1230 [[NSGraphicsContext currentContext] graphicsPort];
1231 static CGAffineTransform fliptf;
1232 static BOOL firstTime = YES;
1237 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1240 CGContextSaveGState (gcontext);
1242 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1244 CGContextSetFont (gcontext, font->cgfont);
1245 CGContextSetFontSize (gcontext, font->size);
1246 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1247 CGContextSetShouldAntialias (gcontext, 0);
1249 CGContextSetShouldAntialias (gcontext, 1);
1251 CGContextSetTextMatrix (gcontext, fliptf);
1255 /* foreground drawing; erase first to avoid overstrike */
1257 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1258 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1259 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1260 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1265 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1266 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1269 if (face->overstrike)
1271 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1272 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1276 CGContextRestoreGState (gcontext);
1278 #endif /* NS_IMPL_COCOA */
1280 /* Draw underline, overline, strike-through. */
1281 ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1289 /* ==========================================================================
1291 Font glyph and metrics caching functions
1293 ========================================================================== */
1295 /* Find and cache corresponding glyph codes for unicode values in given
1296 hi-byte block of 256. */
1298 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1300 #ifdef NS_IMPL_COCOA
1301 static EmacsGlyphStorage *glyphStorage;
1302 static char firstTime = 1;
1304 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1305 unsigned int i, g, idx;
1306 unsigned short *glyphs;
1309 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1314 #ifdef NS_IMPL_COCOA
1318 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1322 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1323 if (!unichars || !(font_info->glyphs[block]))
1326 /* create a string containing all Unicode characters in this block */
1327 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1328 if (idx < 0xD800 || idx > 0xDFFF)
1331 unichars[i] = 0xFEFF;
1332 unichars[0x100] = 0;
1335 #ifdef NS_IMPL_COCOA
1336 NSString *allChars = [[NSString alloc]
1337 initWithCharactersNoCopy: unichars
1340 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1341 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1342 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1343 NSUInteger gInd = 0, cInd = 0;
1345 [glyphStorage setString: allChars font: font_info->nsfont];
1346 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1347 desiredNumberOfCharacters: glyphStorage->maxChar
1348 glyphIndex: &gInd characterIndex: &cInd];
1350 glyphs = font_info->glyphs[block];
1351 for (i = 0; i < 0x100; i++, glyphs++)
1353 #ifdef NS_IMPL_GNUSTEP
1356 g = glyphStorage->cglyphs[i];
1357 /* TODO: is this a good check? maybe need to use coveredChars.. */
1358 if (g > numGlyphs || g == NSNullGlyph)
1359 g = INVALID_GLYPH; /* hopefully unused... */
1364 #ifdef NS_IMPL_COCOA
1374 /* Determine and cache metrics for corresponding glyph codes in given
1375 hi-byte block of 256. */
1377 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1380 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1382 struct font_metrics *metrics;
1385 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1388 #ifdef NS_IMPL_GNUSTEP
1389 /* not implemented yet (as of startup 0.18), so punt */
1391 numGlyphs = 0x10000;
1395 #ifdef NS_IMPL_COCOA
1396 sfont = [font_info->nsfont screenFontWithRenderingMode:
1397 NSFontAntialiasedIntegerAdvancementsRenderingMode];
1399 sfont = [font_info->nsfont screenFont];
1402 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1403 if (!(font_info->metrics[block]))
1406 metrics = font_info->metrics[block];
1407 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1410 NSRect r = [sfont boundingRectForGlyph: g];
1412 w = max ([sfont advancementForGlyph: g].width, 2.0);
1413 metrics->width = lrint (w);
1416 rb = r.size.width - w;
1417 // Add to bearing for LCD smoothing. We don't know if it is there.
1419 metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1420 if (font_info->ital)
1421 rb += (CGFloat) (0.22F * font_info->height);
1422 metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1424 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1425 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1426 metrics->ascent = r.size.height - metrics->descent;
1427 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1433 #ifdef NS_IMPL_COCOA
1434 /* helper for font glyph setup */
1435 @implementation EmacsGlyphStorage
1439 return [self initWithCapacity: 1024];
1442 - initWithCapacity: (unsigned long) c
1444 self = [super init];
1447 dict = [NSMutableDictionary new];
1448 cglyphs = xmalloc (c * sizeof (CGGlyph));
1461 - (void) setString: (NSString *)str font: (NSFont *)font
1463 [dict setObject: font forKey: NSFontAttributeName];
1466 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1467 maxChar = [str length];
1471 /* NSGlyphStorage protocol */
1472 - (NSUInteger)layoutOptions
1477 - (NSAttributedString *)attributedString
1482 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1483 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1484 characterIndex: (NSUInteger)charIndex
1486 len = glyphIndex+length;
1487 for (i =glyphIndex; i<len; i++)
1488 cglyphs[i] = glyphs[i-glyphIndex];
1493 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1494 forGlyphAtIndex: (NSUInteger)glyphIndex
1500 #endif /* NS_IMPL_COCOA */
1505 ns_dump_glyphstring (struct glyph_string *s)
1509 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1510 "overlap = %d, bg_filled = %d:",
1511 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1512 s->row->overlapping_p, s->background_filled_p);
1513 for (i =0; i<s->nchars; i++)
1514 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1515 fprintf (stderr, "\n");
1520 syms_of_nsfont (void)
1522 nsfont_driver.type = Qns;
1523 register_font_driver (&nsfont_driver, NULL);
1524 DEFSYM (Qcondensed, "condensed");
1525 DEFSYM (Qexpanded, "expanded");
1526 DEFSYM (Qapple, "apple");
1527 DEFSYM (Qroman, "roman");
1528 DEFSYM (Qmedium, "medium");
1529 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1530 doc: /* Internal use: maps font registry to Unicode script. */);
1532 ascii_printable = NULL;