1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006, 2007, 2008, 2009 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"
37 #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
47 extern Lisp_Object Qns;
48 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
49 static Lisp_Object Vns_reg_to_script;
50 static Lisp_Object Qapple, Qroman, Qmedium;
51 extern Lisp_Object Qappend;
52 extern int ns_antialias_text;
53 extern float ns_antialias_threshold;
54 extern int ns_tmp_flags;
55 extern struct nsfont_info *ns_tmp_font;
57 /* font glyph and metrics caching functions, implemented at end */
58 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
60 static void ns_glyph_metrics (struct nsfont_info *font_info,
64 /* ==========================================================================
68 ========================================================================== */
71 /* Replace spaces w/another character so emacs core font parsing routines
74 ns_escape_name (char *name)
76 int i =0, len =strlen (name);
83 /* Reconstruct spaces in a font family name passed through emacs. */
85 ns_unescape_name (char *name)
87 int i =0, len =strlen (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 = strdup (SDATA (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.0 : [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.0) / 100.0]
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.0) / 100.0]
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.0) / 100.0]
150 forKey: NSFontWidthTrait];
151 if ([tdict count] > 0)
152 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
154 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
156 fdesc = [fdesc fontDescriptorWithFamily: family];
161 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
163 ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
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 = strdup ([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 free (escapedFamily);
223 /* Default font entity. */
225 ns_fallback_entity ()
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];
239 NSGlyph glyph = [sfont glyphWithName: cstr];
242 float w = [sfont advancementForGlyph: glyph].width;
247 w = [sfont widthOfString: cstr];
252 /* Return whether set1 covers set2 to a reasonable extent given by pct.
253 We check, out of each 16 unicode char range containing chars in set2,
254 whether at least one character is present in set1.
255 This must be true for pct of the pairs to consider it covering. */
257 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
259 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
260 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
261 int i, off = 0, tot = 0;
263 for (i=0; i<4096; i++, bytes1++, bytes2++)
267 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
270 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
271 return (float)off / tot < 1.0 - pct;
275 /* Convert :lang property to a script. Use of :lang property by font backend
276 seems to be limited for now (2009/05) to ja, zh, and ko. */
278 *ns_lang_to_script (Lisp_Object lang)
280 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
282 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
283 have more characters. */
284 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
286 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
293 /* Convert OTF 4-letter script code to emacs script name. (Why can't
294 everyone just use some standard unicode names for these?) */
296 *ns_otf_to_script (Lisp_Object otf)
298 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
299 return CONSP (script)
300 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
305 /* Convert a font registry, such as */
307 *ns_registry_to_script (char *reg)
309 Lisp_Object script, r, rts = Vns_reg_to_script;
312 r = XCAR (XCAR (rts));
313 if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
315 script = XCDR (XCAR (rts));
316 return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
324 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
325 plus registry regular property, for something that can be mapped to a
326 unicode script. Empty string returned if no script spec found. */
328 *ns_get_req_script (Lisp_Object font_spec)
330 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
331 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
333 /* The extra-bundle properties have priority. */
334 for ( ; CONSP (extra); extra = XCDR (extra))
336 Lisp_Object tmp = XCAR (extra);
339 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
340 if (EQ (key, QCscript) && SYMBOLP (val))
341 return [NSString stringWithUTF8String:
342 SDATA (SYMBOL_NAME (val))];
343 if (EQ (key, QClang) && SYMBOLP (val))
344 return ns_lang_to_script (val);
345 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
346 return ns_otf_to_script (val);
350 /* If we get here, check the charset portion of the registry. */
353 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
354 (which causes box rendering if we don't treat it like iso8858-1)
355 but also for ascii (which causes unnecessary font substitution). */
357 if (EQ (reg, Qiso10646_1))
360 return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
367 /* This small function is static in fontset.c. If it can be made public for
368 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
370 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
372 if (EQ (XCAR (arg), val))
375 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
377 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
382 /* Use the unicode range information in Vchar_script_table to convert a script
383 name into an NSCharacterSet. */
384 static NSCharacterSet
385 *ns_script_to_charset (NSString *scriptName)
387 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
388 Lisp_Object script = intern ([scriptName UTF8String]);
389 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
391 if (! NILP (Fmemq (script, script_list)))
393 Lisp_Object ranges, range_list;
395 ranges = Fcons (script, Qnil);
396 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
398 range_list = Fnreverse (XCDR (ranges));
399 if (! NILP (range_list))
401 for (; CONSP (range_list); range_list = XCDR (range_list))
403 int start = XINT (XCAR (XCAR (range_list)));
404 int end = XINT (XCDR (XCAR (range_list)));
406 debug_print (XCAR (range_list));
408 [charset addCharactersInRange:
409 NSMakeRange (start, end-start)];
417 /* Return an array of font families containing characters for the given
418 script, for the given coverage criterion, including at least LastResort.
419 Results are cached by script for faster access.
420 If none are found, we reduce the percentage and try again, until 5%.
421 This provides a font with at least some characters if such can be found.
422 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
423 (b) need approximate match as fonts covering full unicode ranges are rare. */
425 *ns_get_covering_families (NSString *script, float pct)
427 static NSMutableDictionary *scriptToFamilies = nil;
428 NSMutableSet *families;
431 NSLog(@"Request covering families for script: '%@'", script);
433 if (scriptToFamilies == nil)
434 scriptToFamilies = [[NSMutableDictionary alloc] init];
436 if ((families = [scriptToFamilies objectForKey: script]) == nil)
438 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
439 NSArray *allFamilies = [fontMgr availableFontFamilies];
441 if ([script length] == 0)
442 families = [NSMutableSet setWithArray: allFamilies];
445 NSCharacterSet *charset = ns_script_to_charset (script);
447 families = [NSMutableSet setWithCapacity: 10];
450 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
451 while (family = [allFamiliesEnum nextObject])
453 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
454 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
455 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
457 fset = [NSCharacterSet characterSetWithRange:
458 NSMakeRange (0, 127)];
459 if (ns_charset_covers(fset, charset, pct))
460 [families addObject: family];
463 if ([families count] > 0 || pct < 0.05)
468 if ([families count] == 0)
469 [families addObject: @"LastResort"];
471 [scriptToFamilies setObject: families forKey: script];
475 NSLog(@" returning %d families", [families count]);
480 /* Implementation for list() and match(). List() can return nil, match()
481 must return something. Strategy is to drop family name from attribute
482 matching set for match. */
484 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
486 Lisp_Object tem, list = Qnil;
487 NSFontDescriptor *fdesc, *desc;
489 NSArray *matchingDescs;
497 fprintf (stderr, "nsfont: %s for fontspec:\n ",
498 (isMatch ? "match" : "list"));
499 debug_print (font_spec);
502 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
504 fdesc = ns_spec_to_descriptor (font_spec);
505 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
507 [fkeys removeObject: NSFontFamilyAttribute];
509 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
511 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
512 [matchingDescs count]);
514 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
516 if (![cFamilies containsObject:
517 [desc objectForKey: NSFontFamilyAttribute]])
519 tem = ns_descriptor_to_entity (desc,
520 AREF (font_spec, FONT_EXTRA_INDEX),
524 list = Fcons (tem, list);
525 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
529 /* Add synthItal member if needed. */
530 family = [fdesc objectForKey: NSFontFamilyAttribute];
531 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
533 NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
534 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
535 fontDescriptorWithFamily: family];
536 list = Fcons (ns_descriptor_to_entity (sDesc,
537 AREF (font_spec, FONT_EXTRA_INDEX),
541 /* Return something if was a match and nothing found. */
543 return ns_fallback_entity ();
546 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
553 /* ==========================================================================
555 Font driver implementation
557 ========================================================================== */
560 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
561 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
562 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
563 static Lisp_Object nsfont_list_family (Lisp_Object frame);
564 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
566 static void nsfont_close (FRAME_PTR f, struct font *font);
567 static int nsfont_has_char (Lisp_Object entity, int c);
568 static unsigned int nsfont_encode_char (struct font *font, int c);
569 static int nsfont_text_extents (struct font *font, unsigned int *code,
570 int nglyphs, struct font_metrics *metrics);
571 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
572 int with_background);
574 struct font_driver nsfont_driver =
577 1, /* case sensitive */
582 NULL, /*free_entity */
585 NULL, /* prepare_face */
586 NULL, /* done_face */
591 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
592 anchor_point, otf_capability, otf_driver,
593 start_for_frame, end_for_frame, shape */
597 /* Return a cache of font-entities on FRAME. The cache must be a
598 cons whose cdr part is the actual cache area. */
600 nsfont_get_cache (FRAME_PTR frame)
602 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
603 return (dpyinfo->name_list_element);
607 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
608 **list** of font-entities. This and match () are sole APIs that allocate
609 font-entities. Properties to be considered (2009/05/19) are:
610 regular: foundry, family, adstyle, registry
611 extended: script, lang, otf
612 "Extended" properties are not part of the vector but get stored as
613 lisp properties under FONT_EXTRA_INDEX.
615 The returned entities should have type set (to 'ns), plus the following:
616 foundry, family, adstyle, registry,
617 weight, slant, width, size (0 if scalable),
618 dpi, spacing, avgwidth (0 if scalable) */
620 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
622 return ns_findfonts (font_spec, NO);
626 /* Return a font entity most closely maching with FONT_SPEC on
627 FRAME. The closeness is determined by the font backend, thus
628 `face-font-selection-order' is ignored here.
629 Properties to be considered are same as for list(). */
631 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
633 return ns_findfonts(font_spec, YES);
637 /* List available families. The value is a list of family names
640 nsfont_list_family (Lisp_Object frame)
642 Lisp_Object list = Qnil;
643 NSEnumerator *families =
644 [[[NSFontManager sharedFontManager] availableFontFamilies]
647 while (family = [families nextObject])
648 list = Fcons (intern ([family UTF8String]), list);
649 /* FIXME: escape the name? */
652 fprintf (stderr, "nsfont: list families returning %d entries\n",
653 XINT (Flength (list)));
659 /* Open a font specified by FONT_ENTITY on frame F. If the font is
660 scalable, open it with PIXEL_SIZE. */
662 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
665 unsigned int traits = 0;
666 struct nsfont_info *font_info;
668 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
669 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
671 NSFont *nsfont, *sfont;
674 Lisp_Object font_object;
677 static NSMutableDictionary *fontCache = nil;
680 /* 2008/03/08: The same font may end up being requested for different
681 entities, due to small differences in numeric values or other issues,
682 or for different copies of the same entity. Therefore we cache to
683 avoid creating multiple struct font objects (with metrics cache, etc.)
684 for the same NSFont object. */
685 if (fontCache == nil)
686 fontCache = [[NSMutableDictionary alloc] init];
690 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
691 debug_print (font_entity);
696 /* try to get it out of frame params */
697 Lisp_Object tem = get_frame_param (f, Qfontsize);
698 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
701 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
702 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
704 family = ns_get_family (font_entity);
706 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
707 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
708 when setting family in ns_spec_to_descriptor(). */
709 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
710 traits |= NSBoldFontMask;
711 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
712 traits |= NSItalicFontMask;
714 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
715 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
716 nsfont = [fontMgr fontWithFamily: family
717 traits: traits weight: fixLeopardBug
719 /* if didn't find, try synthetic italic */
720 if (nsfont == nil && synthItal)
722 nsfont = [fontMgr fontWithFamily: family
723 traits: traits & ~NSItalicFontMask
724 weight: fixLeopardBug size: pixel_size];
727 /* LastResort not really a family */
728 if (nsfont == nil && [@"LastResort" isEqualToString: family])
729 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
734 message_with_string ("*** Warning: font in family '%s' not found",
735 build_string ([family UTF8String]), 1);
736 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
740 NSLog (@"%@\n", nsfont);
742 /* Check the cache */
743 cached = [fontCache objectForKey: nsfont];
744 if (cached != nil && !synthItal)
747 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
748 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
749 XHASH (font_object) = [cached unsignedLongValue];
754 font_object = font_make_object (VECSIZE (struct nsfont_info),
755 font_entity, pixel_size);
757 [fontCache setObject: [NSNumber numberWithUnsignedLong:
758 (unsigned long) XHASH (font_object)]
762 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
763 font = (struct font *) font_info;
765 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
767 font_info->glyphs = (unsigned short **)
768 xmalloc (0x100 * sizeof (unsigned short *));
769 font_info->metrics = (struct font_metrics **)
770 xmalloc (0x100 * sizeof (struct font_metrics *));
771 if (!font_info->glyphs || !font_info->metrics)
773 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
774 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
779 sfont = [nsfont screenFont];
783 /* non-metric backend font struct fields */
784 font = (struct font *) font_info;
785 font->pixel_size = [sfont pointSize];
786 font->driver = &nsfont_driver;
787 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
788 font->encoding_charset = -1;
789 font->repertory_charset = -1;
790 font->default_ascent = 0;
791 font->vertical_centering = 0;
792 font->baseline_offset = 0;
793 font->relative_compose = 0;
794 font->font_encoder = NULL;
796 font->props[FONT_FORMAT_INDEX] = Qns;
797 font->props[FONT_FILE_INDEX] = Qnil;
800 double expand, hshrink;
801 float full_height, min_height, hd;
802 const char *fontName = [[nsfont fontName] UTF8String];
803 int len = strlen (fontName);
805 #ifdef NS_IMPL_GNUSTEP
806 font_info->nsfont = sfont;
808 font_info->nsfont = nsfont;
810 [font_info->nsfont retain];
812 /* set up ns_font (defined in nsgui.h) */
813 font_info->name = (char *)xmalloc (strlen (fontName) + 1);
814 bcopy (fontName, font_info->name, strlen (fontName) + 1);
815 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
817 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
819 /* Metrics etc.; some fonts return an unusually large max advance, so we
820 only use it for fonts that have wide characters. */
821 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
822 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
824 brect = [sfont boundingRectForFont];
825 full_height = brect.size.height;
826 min_height = [sfont ascender] - [sfont descender];
827 hd = full_height - min_height;
829 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
833 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
834 font_info->underwidth = [sfont underlineThickness];
835 font_info->size = font->pixel_size;
836 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
839 font_info->max_bounds.ascent =
840 lrint (hshrink * [sfont ascender] + expand * hd/2);
841 font_info->max_bounds.descent =
842 -lrint (hshrink* [sfont descender] - expand*hd/2);
844 font_info->max_bounds.ascent + font_info->max_bounds.descent;
845 font_info->max_bounds.width = lrint (font_info->width);
846 font_info->max_bounds.lbearing = lrint (brect.origin.x);
847 font_info->max_bounds.rbearing =
848 lrint (brect.size.width - font_info->width);
851 /* set up synthItal and the CG font */
852 font_info->synthItal = synthItal;
854 ATSFontRef atsFont = ATSFontFindFromPostScriptName
855 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
857 if (atsFont == kATSFontRefUnspecified)
859 /* see if we can get it by dropping italic (then synthesizing) */
860 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
861 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
862 fontName], kATSOptionFlagsDefault);
863 if (atsFont != kATSFontRefUnspecified)
864 font_info->synthItal = YES;
867 /* last resort fallback */
868 atsFont = ATSFontFindFromPostScriptName
869 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
872 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
876 /* set up metrics portion of font struct */
877 font->ascent = [sfont ascender];
878 font->descent = -[sfont descender];
879 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
880 font->space_width = lrint (ns_char_width (sfont, ' '));
881 font->average_width = lrint (font_info->width);
882 font->max_width = lrint (font_info->max_bounds.width);
883 font->height = lrint (font_info->height);
884 font->underline_position = lrint (font_info->underpos);
885 font->underline_thickness = lrint (font_info->underwidth);
887 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
888 font->props[FONT_FULLNAME_INDEX] =
889 make_unibyte_string (font_info->name, strlen (font_info->name));
897 /* Close FONT on frame F. */
899 nsfont_close (FRAME_PTR f, struct font *font)
901 struct nsfont_info *font_info = (struct nsfont_info *)font;
904 /* FIXME: this occurs apparently due to same failure to detect same font
905 that causes need for cache in nsfont_open () */
909 for (i =0; i<0x100; i++)
911 xfree (font_info->glyphs[i]);
912 xfree (font_info->metrics[i]);
914 [font_info->nsfont release];
916 CGFontRelease (font_info->cgfont);
918 xfree (font_info->name);
923 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
924 return 1. If not, return 0. If a font must be opened to check
927 nsfont_has_char (Lisp_Object entity, int c)
933 /* Return a glyph code of FONT for character C (Unicode code point).
934 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
936 nsfont_encode_char (struct font *font, int c)
938 struct nsfont_info *font_info = (struct nsfont_info *)font;
939 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
943 return FONT_INVALID_CODE;
945 /* did we already cache this block? */
946 if (!font_info->glyphs[high])
947 ns_uni_to_glyphs (font_info, high);
949 g = font_info->glyphs[high][low];
950 return g == 0xFFFF ? FONT_INVALID_CODE : g;
954 /* Perform the size computation of glyphs of FONT and fill in members
955 of METRICS. The glyphs are specified by their glyph codes in
956 CODE (length NGLYPHS). */
958 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
959 struct font_metrics *metrics)
961 struct nsfont_info *font_info = (struct nsfont_info *)font;
962 struct font_metrics *pcm;
963 unsigned char high, low;
967 bzero (metrics, sizeof (struct font_metrics));
969 for (i =0; i<nglyphs; i++)
971 /* get metrics for this glyph, filling cache if need be */
972 /* TODO: get metrics for whole string from an NSLayoutManager
974 high = (code[i] & 0xFF00) >> 8;
975 low = code[i] & 0x00FF;
976 if (!font_info->metrics[high])
977 ns_glyph_metrics (font_info, high);
978 pcm = &(font_info->metrics[high][low]);
980 if (metrics->lbearing > totalWidth + pcm->lbearing)
981 metrics->lbearing = totalWidth + pcm->lbearing;
982 if (metrics->rbearing < totalWidth + pcm->rbearing)
983 metrics->rbearing = totalWidth + pcm->rbearing;
984 if (metrics->ascent < pcm->ascent)
985 metrics->ascent = pcm->ascent;
986 if (metrics->descent < pcm->descent)
987 metrics->descent = pcm->descent;
989 totalWidth += pcm->width;
992 metrics->width = totalWidth;
994 return totalWidth; /* not specified in doc, but xfont.c does it */
998 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
999 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
1000 is nonzero, fill the background in advance. It is assured that
1001 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1003 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1004 int with_background)
1005 /* NOTE: focus and clip must be set
1006 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1008 static char cbuf[1024];
1010 #ifdef NS_IMPL_GNUSTEP
1011 static float advances[1024];
1012 float *adv = advances;
1014 static CGSize advances[1024];
1015 CGSize *adv = advances;
1019 struct nsfont_info *font = ns_tmp_font;
1020 NSColor *col, *bgCol;
1021 unsigned short *t = s->char2b;
1023 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1024 int end = isComposite ? s->cmp_to : s->nchars;
1026 /* Select face based on input flags */
1027 switch (ns_tmp_flags)
1029 case NS_DUMPGLYPH_CURSOR:
1032 case NS_DUMPGLYPH_MOUSEFACE:
1033 face = FACE_FROM_ID (s->f,
1034 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1036 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1043 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1044 r.origin.x += abs (s->face->box_line_width);
1047 r.size.height = FONT_HEIGHT (font);
1049 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1050 NS to render the string, it will come out differently from the individual
1051 character widths added up because of layout processing. */
1054 int cwidth, twidth = 0;
1056 /* FIXME: composition: no vertical displacement is considered. */
1057 t += s->cmp_from; /* advance into composition */
1058 for (i = s->cmp_from; i < end; 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_NS_DISPLAY_INFO (s->f);
1145 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1151 /* set up for character rendering */
1152 r.origin.y += font->voffset + (s->height - font->height)/2;
1154 col = (NS_FACE_FOREGROUND (face) != 0
1155 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1156 : FRAME_FOREGROUND_COLOR (s->f));
1157 /* FIXME: find another way to pass this */
1158 bgCol = (ns_tmp_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, cbuf, advances, len);
1178 DPSstroke (context);
1180 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1184 if (face->underline_p)
1186 if (face->underline_color != 0)
1187 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1190 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1191 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1192 if (face->underline_color != 0)
1198 /* draw with DPSxshow () */
1199 DPSmoveto (context, r.origin.x, r.origin.y);
1200 DPSxshow (context, cbuf, advances, len);
1201 DPSstroke (context);
1203 DPSgrestore (context);
1207 #else /* NS_IMPL_COCOA */
1209 CGContextRef gcontext =
1210 [[NSGraphicsContext currentContext] graphicsPort];
1211 static CGAffineTransform fliptf;
1212 static BOOL firstTime = YES;
1217 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1220 CGContextSaveGState (gcontext);
1222 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1224 CGContextSetFont (gcontext, font->cgfont);
1225 CGContextSetFontSize (gcontext, font->size);
1226 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1227 CGContextSetShouldAntialias (gcontext, 0);
1229 CGContextSetShouldAntialias (gcontext, 1);
1231 CGContextSetTextMatrix (gcontext, fliptf);
1235 /* foreground drawing; erase first to avoid overstrike */
1237 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1238 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1239 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1240 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1243 if (face->underline_p)
1245 if (face->underline_color != 0)
1246 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1249 CGContextBeginPath (gcontext);
1250 CGContextMoveToPoint (gcontext,
1251 r.origin.x, r.origin.y + font->underpos);
1252 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1253 r.origin.y + font->underpos);
1254 CGContextStrokePath (gcontext);
1255 if (face->underline_color != 0)
1261 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1262 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1265 if (face->overstrike)
1267 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1268 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1272 CGContextRestoreGState (gcontext);
1275 #endif /* NS_IMPL_COCOA */
1281 /* ==========================================================================
1283 Font glyph and metrics caching functions
1285 ========================================================================== */
1287 /* Find and cache corresponding glyph codes for unicode values in given
1288 hi-byte block of 256. */
1290 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1292 #ifdef NS_IMPL_COCOA
1293 static EmacsGlyphStorage *glyphStorage;
1294 static char firstTime = 1;
1296 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1297 unsigned int i, g, idx;
1298 unsigned short *glyphs;
1301 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1306 #ifdef NS_IMPL_COCOA
1310 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1314 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1315 if (!unichars || !(font_info->glyphs[block]))
1318 /* create a string containing all unicode characters in this block */
1319 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1320 if (idx < 0xD800 || idx > 0xDFFF)
1323 unichars[i] = 0xFEFF;
1324 unichars[0x100] = 0;
1327 #ifdef NS_IMPL_COCOA
1328 NSString *allChars = [[NSString alloc]
1329 initWithCharactersNoCopy: unichars
1332 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1333 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1334 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1335 unsigned int gInd =0, cInd =0;
1337 [glyphStorage setString: allChars font: font_info->nsfont];
1338 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1339 desiredNumberOfCharacters: glyphStorage->maxChar
1340 glyphIndex: &gInd characterIndex: &cInd];
1342 glyphs = font_info->glyphs[block];
1343 for (i =0; i<0x100; i++, glyphs++)
1345 #ifdef NS_IMPL_GNUSTEP
1348 g = glyphStorage->cglyphs[i];
1349 /* TODO: is this a good check? maybe need to use coveredChars.. */
1351 g = 0xFFFF; /* hopefully unused... */
1356 #ifdef NS_IMPL_COCOA
1366 /* Determine and cache metrics for corresponding glyph codes in given
1367 hi-byte block of 256. */
1369 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1372 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1374 struct font_metrics *metrics;
1377 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1380 #ifdef NS_IMPL_GNUSTEP
1381 /* not implemented yet (as of startup 0.18), so punt */
1383 numGlyphs = 0x10000;
1387 sfont = [font_info->nsfont screenFont];
1389 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1390 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1391 if (!(font_info->metrics[block]))
1394 metrics = font_info->metrics[block];
1395 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1398 NSRect r = [sfont boundingRectForGlyph: g];
1400 w = max ([sfont advancementForGlyph: g].width, 2.0);
1401 metrics->width = lrint (w);
1404 rb = r.size.width - w;
1406 metrics->lbearing = round (lb);
1407 if (font_info->ital)
1408 rb += 0.22 * font_info->height;
1409 metrics->rbearing = lrint (w + rb);
1411 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1412 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1413 metrics->ascent = r.size.height - metrics->descent;
1414 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1420 #ifdef NS_IMPL_COCOA
1421 /* helper for font glyph setup */
1422 @implementation EmacsGlyphStorage
1426 return [self initWithCapacity: 1024];
1429 - initWithCapacity: (unsigned long) c
1431 self = [super init];
1434 dict = [NSMutableDictionary new];
1435 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1448 - (void) setString: (NSString *)str font: (NSFont *)font
1450 [dict setObject: font forKey: NSFontAttributeName];
1451 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1452 maxChar = [str length];
1456 /* NSGlyphStorage protocol */
1457 - (unsigned int)layoutOptions
1462 - (NSAttributedString *)attributedString
1467 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1468 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1469 characterIndex: (unsigned int)charIndex
1471 len = glyphIndex+length;
1472 for (i =glyphIndex; i<len; i++)
1473 cglyphs[i] = glyphs[i-glyphIndex];
1478 - (void)setIntAttribute: (int)attributeTag value: (int)val
1479 forGlyphAtIndex: (unsigned)glyphIndex
1485 #endif /* NS_IMPL_COCOA */
1490 ns_dump_glyphstring (struct glyph_string *s)
1494 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1495 "overlap = %d, bg_filled = %d:",
1496 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1497 s->row->overlapping_p, s->background_filled_p);
1498 for (i =0; i<s->nchars; i++)
1499 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1500 fprintf (stderr, "\n");
1507 nsfont_driver.type = Qns;
1508 register_font_driver (&nsfont_driver, NULL);
1509 DEFSYM (Qapple, "apple");
1510 DEFSYM (Qroman, "roman");
1511 DEFSYM (Qmedium, "medium");
1512 DEFVAR_LISP ("ns-reg-to-script", &Vns_reg_to_script,
1513 doc: /* Internal use: maps font registry to unicode script. */);
1516 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae