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;
248 NSDictionary *attrsDictionary =
249 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
250 w = [cstr sizeWithAttributes: attrsDictionary].width;
256 /* Return whether set1 covers set2 to a reasonable extent given by pct.
257 We check, out of each 16 unicode char range containing chars in set2,
258 whether at least one character is present in set1.
259 This must be true for pct of the pairs to consider it covering. */
261 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
263 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
264 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
265 int i, off = 0, tot = 0;
267 for (i=0; i<4096; i++, bytes1++, bytes2++)
271 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
274 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
275 return (float)off / tot < 1.0 - pct;
279 /* Convert :lang property to a script. Use of :lang property by font backend
280 seems to be limited for now (2009/05) to ja, zh, and ko. */
282 *ns_lang_to_script (Lisp_Object lang)
284 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
286 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
287 have more characters. */
288 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
290 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
297 /* Convert OTF 4-letter script code to emacs script name. (Why can't
298 everyone just use some standard unicode names for these?) */
300 *ns_otf_to_script (Lisp_Object otf)
302 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
303 return CONSP (script)
304 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
309 /* Convert a font registry, such as */
311 *ns_registry_to_script (char *reg)
313 Lisp_Object script, r, rts = Vns_reg_to_script;
316 r = XCAR (XCAR (rts));
317 if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
319 script = XCDR (XCAR (rts));
320 return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
328 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
329 plus registry regular property, for something that can be mapped to a
330 unicode script. Empty string returned if no script spec found. */
332 *ns_get_req_script (Lisp_Object font_spec)
334 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
335 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
337 /* The extra-bundle properties have priority. */
338 for ( ; CONSP (extra); extra = XCDR (extra))
340 Lisp_Object tmp = XCAR (extra);
343 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
344 if (EQ (key, QCscript) && SYMBOLP (val))
345 return [NSString stringWithUTF8String:
346 SDATA (SYMBOL_NAME (val))];
347 if (EQ (key, QClang) && SYMBOLP (val))
348 return ns_lang_to_script (val);
349 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
350 return ns_otf_to_script (val);
354 /* If we get here, check the charset portion of the registry. */
357 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
358 (which causes box rendering if we don't treat it like iso8858-1)
359 but also for ascii (which causes unnecessary font substitution). */
361 if (EQ (reg, Qiso10646_1))
364 return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
371 /* This small function is static in fontset.c. If it can be made public for
372 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
374 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
376 if (EQ (XCAR (arg), val))
379 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
381 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
386 /* Use the unicode range information in Vchar_script_table to convert a script
387 name into an NSCharacterSet. */
388 static NSCharacterSet
389 *ns_script_to_charset (NSString *scriptName)
391 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
392 Lisp_Object script = intern ([scriptName UTF8String]);
393 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
395 if (! NILP (Fmemq (script, script_list)))
397 Lisp_Object ranges, range_list;
399 ranges = Fcons (script, Qnil);
400 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
402 range_list = Fnreverse (XCDR (ranges));
403 if (! NILP (range_list))
405 for (; CONSP (range_list); range_list = XCDR (range_list))
407 int start = XINT (XCAR (XCAR (range_list)));
408 int end = XINT (XCDR (XCAR (range_list)));
410 debug_print (XCAR (range_list));
412 [charset addCharactersInRange:
413 NSMakeRange (start, end-start)];
421 /* Return an array of font families containing characters for the given
422 script, for the given coverage criterion, including at least LastResort.
423 Results are cached by script for faster access.
424 If none are found, we reduce the percentage and try again, until 5%.
425 This provides a font with at least some characters if such can be found.
426 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
427 (b) need approximate match as fonts covering full unicode ranges are rare. */
429 *ns_get_covering_families (NSString *script, float pct)
431 static NSMutableDictionary *scriptToFamilies = nil;
432 NSMutableSet *families;
435 NSLog(@"Request covering families for script: '%@'", script);
437 if (scriptToFamilies == nil)
438 scriptToFamilies = [[NSMutableDictionary alloc] init];
440 if ((families = [scriptToFamilies objectForKey: script]) == nil)
442 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
443 NSArray *allFamilies = [fontMgr availableFontFamilies];
445 if ([script length] == 0)
446 families = [NSMutableSet setWithArray: allFamilies];
449 NSCharacterSet *charset = ns_script_to_charset (script);
451 families = [NSMutableSet setWithCapacity: 10];
454 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
455 while (family = [allFamiliesEnum nextObject])
457 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
458 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
459 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
461 fset = [NSCharacterSet characterSetWithRange:
462 NSMakeRange (0, 127)];
463 if (ns_charset_covers(fset, charset, pct))
464 [families addObject: family];
467 if ([families count] > 0 || pct < 0.05)
472 if ([families count] == 0)
473 [families addObject: @"LastResort"];
475 [scriptToFamilies setObject: families forKey: script];
479 NSLog(@" returning %d families", [families count]);
484 /* Implementation for list() and match(). List() can return nil, match()
485 must return something. Strategy is to drop family name from attribute
486 matching set for match. */
488 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
490 Lisp_Object tem, list = Qnil;
491 NSFontDescriptor *fdesc, *desc;
493 NSArray *matchingDescs;
501 fprintf (stderr, "nsfont: %s for fontspec:\n ",
502 (isMatch ? "match" : "list"));
503 debug_print (font_spec);
506 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
508 fdesc = ns_spec_to_descriptor (font_spec);
509 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
511 [fkeys removeObject: NSFontFamilyAttribute];
513 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
515 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
516 [matchingDescs count]);
518 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
520 if (![cFamilies containsObject:
521 [desc objectForKey: NSFontFamilyAttribute]])
523 tem = ns_descriptor_to_entity (desc,
524 AREF (font_spec, FONT_EXTRA_INDEX),
528 list = Fcons (tem, list);
529 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
533 /* Add synthItal member if needed. */
534 family = [fdesc objectForKey: NSFontFamilyAttribute];
535 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
537 NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
538 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
539 fontDescriptorWithFamily: family];
540 list = Fcons (ns_descriptor_to_entity (sDesc,
541 AREF (font_spec, FONT_EXTRA_INDEX),
545 /* Return something if was a match and nothing found. */
547 return ns_fallback_entity ();
550 fprintf (stderr, " Returning %ld entities.\n",
551 (long) XINT (Flength (list)));
558 /* ==========================================================================
560 Font driver implementation
562 ========================================================================== */
565 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
566 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
567 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
568 static Lisp_Object nsfont_list_family (Lisp_Object frame);
569 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
571 static void nsfont_close (FRAME_PTR f, struct font *font);
572 static int nsfont_has_char (Lisp_Object entity, int c);
573 static unsigned int nsfont_encode_char (struct font *font, int c);
574 static int nsfont_text_extents (struct font *font, unsigned int *code,
575 int nglyphs, struct font_metrics *metrics);
576 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
577 int with_background);
579 struct font_driver nsfont_driver =
582 1, /* case sensitive */
587 NULL, /*free_entity */
590 NULL, /* prepare_face */
591 NULL, /* done_face */
596 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
597 anchor_point, otf_capability, otf_driver,
598 start_for_frame, end_for_frame, shape */
602 /* Return a cache of font-entities on FRAME. The cache must be a
603 cons whose cdr part is the actual cache area. */
605 nsfont_get_cache (FRAME_PTR frame)
607 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
608 return (dpyinfo->name_list_element);
612 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
613 **list** of font-entities. This and match () are sole APIs that allocate
614 font-entities. Properties to be considered (2009/05/19) are:
615 regular: foundry, family, adstyle, registry
616 extended: script, lang, otf
617 "Extended" properties are not part of the vector but get stored as
618 lisp properties under FONT_EXTRA_INDEX.
620 The returned entities should have type set (to 'ns), plus the following:
621 foundry, family, adstyle, registry,
622 weight, slant, width, size (0 if scalable),
623 dpi, spacing, avgwidth (0 if scalable) */
625 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
627 return ns_findfonts (font_spec, NO);
631 /* Return a font entity most closely maching with FONT_SPEC on
632 FRAME. The closeness is determined by the font backend, thus
633 `face-font-selection-order' is ignored here.
634 Properties to be considered are same as for list(). */
636 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
638 return ns_findfonts(font_spec, YES);
642 /* List available families. The value is a list of family names
645 nsfont_list_family (Lisp_Object frame)
647 Lisp_Object list = Qnil;
648 NSEnumerator *families =
649 [[[NSFontManager sharedFontManager] availableFontFamilies]
652 while (family = [families nextObject])
653 list = Fcons (intern ([family UTF8String]), list);
654 /* FIXME: escape the name? */
657 fprintf (stderr, "nsfont: list families returning %ld entries\n",
658 (long) XINT (Flength (list)));
664 /* Open a font specified by FONT_ENTITY on frame F. If the font is
665 scalable, open it with PIXEL_SIZE. */
667 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
670 unsigned int traits = 0;
671 struct nsfont_info *font_info;
673 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
674 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
676 NSFont *nsfont, *sfont;
679 Lisp_Object font_object;
682 static NSMutableDictionary *fontCache = nil;
685 /* 2008/03/08: The same font may end up being requested for different
686 entities, due to small differences in numeric values or other issues,
687 or for different copies of the same entity. Therefore we cache to
688 avoid creating multiple struct font objects (with metrics cache, etc.)
689 for the same NSFont object. */
690 if (fontCache == nil)
691 fontCache = [[NSMutableDictionary alloc] init];
695 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
696 debug_print (font_entity);
701 /* try to get it out of frame params */
702 Lisp_Object tem = get_frame_param (f, Qfontsize);
703 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
706 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
707 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
709 family = ns_get_family (font_entity);
711 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
712 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
713 when setting family in ns_spec_to_descriptor(). */
714 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
715 traits |= NSBoldFontMask;
716 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
717 traits |= NSItalicFontMask;
719 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
720 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
721 nsfont = [fontMgr fontWithFamily: family
722 traits: traits weight: fixLeopardBug
724 /* if didn't find, try synthetic italic */
725 if (nsfont == nil && synthItal)
727 nsfont = [fontMgr fontWithFamily: family
728 traits: traits & ~NSItalicFontMask
729 weight: fixLeopardBug size: pixel_size];
732 /* LastResort not really a family */
733 if (nsfont == nil && [@"LastResort" isEqualToString: family])
734 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
739 message_with_string ("*** Warning: font in family '%s' not found",
740 build_string ([family UTF8String]), 1);
741 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
745 NSLog (@"%@\n", nsfont);
747 /* Check the cache */
748 cached = [fontCache objectForKey: nsfont];
749 if (cached != nil && !synthItal)
752 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
753 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
754 XHASH (font_object) = [cached unsignedLongValue];
759 font_object = font_make_object (VECSIZE (struct nsfont_info),
760 font_entity, pixel_size);
762 [fontCache setObject: [NSNumber numberWithUnsignedLong:
763 (unsigned long) XHASH (font_object)]
767 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
768 font = (struct font *) font_info;
770 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
772 font_info->glyphs = (unsigned short **)
773 xmalloc (0x100 * sizeof (unsigned short *));
774 font_info->metrics = (struct font_metrics **)
775 xmalloc (0x100 * sizeof (struct font_metrics *));
776 if (!font_info->glyphs || !font_info->metrics)
778 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
779 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
784 sfont = [nsfont screenFont];
788 /* non-metric backend font struct fields */
789 font = (struct font *) font_info;
790 font->pixel_size = [sfont pointSize];
791 font->driver = &nsfont_driver;
792 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
793 font->encoding_charset = -1;
794 font->repertory_charset = -1;
795 font->default_ascent = 0;
796 font->vertical_centering = 0;
797 font->baseline_offset = 0;
798 font->relative_compose = 0;
799 font->font_encoder = NULL;
801 font->props[FONT_FORMAT_INDEX] = Qns;
802 font->props[FONT_FILE_INDEX] = Qnil;
805 double expand, hshrink;
806 float full_height, min_height, hd;
807 const char *fontName = [[nsfont fontName] UTF8String];
808 int len = strlen (fontName);
810 #ifdef NS_IMPL_GNUSTEP
811 font_info->nsfont = sfont;
813 font_info->nsfont = nsfont;
815 [font_info->nsfont retain];
817 /* set up ns_font (defined in nsgui.h) */
818 font_info->name = (char *)xmalloc (strlen (fontName) + 1);
819 bcopy (fontName, font_info->name, strlen (fontName) + 1);
820 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
822 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
824 /* Metrics etc.; some fonts return an unusually large max advance, so we
825 only use it for fonts that have wide characters. */
826 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
827 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
829 brect = [sfont boundingRectForFont];
830 full_height = brect.size.height;
831 min_height = [sfont ascender] - [sfont descender];
832 hd = full_height - min_height;
834 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
838 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
839 font_info->underwidth = [sfont underlineThickness];
840 font_info->size = font->pixel_size;
841 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
844 font_info->max_bounds.ascent =
845 lrint (hshrink * [sfont ascender] + expand * hd/2);
846 font_info->max_bounds.descent =
847 -lrint (hshrink* [sfont descender] - expand*hd/2);
849 font_info->max_bounds.ascent + font_info->max_bounds.descent;
850 font_info->max_bounds.width = lrint (font_info->width);
851 font_info->max_bounds.lbearing = lrint (brect.origin.x);
852 font_info->max_bounds.rbearing =
853 lrint (brect.size.width - font_info->width);
856 /* set up synthItal and the CG font */
857 font_info->synthItal = synthItal;
859 ATSFontRef atsFont = ATSFontFindFromPostScriptName
860 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
862 if (atsFont == kATSFontRefUnspecified)
864 /* see if we can get it by dropping italic (then synthesizing) */
865 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
866 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
867 fontName], kATSOptionFlagsDefault);
868 if (atsFont != kATSFontRefUnspecified)
869 font_info->synthItal = YES;
872 /* last resort fallback */
873 atsFont = ATSFontFindFromPostScriptName
874 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
877 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
881 /* set up metrics portion of font struct */
882 font->ascent = [sfont ascender];
883 font->descent = -[sfont descender];
884 font->min_width = ns_char_width(sfont, '|');
885 font->space_width = lrint (ns_char_width (sfont, ' '));
886 font->average_width = lrint (font_info->width);
887 font->max_width = lrint (font_info->max_bounds.width);
888 font->height = lrint (font_info->height);
889 font->underline_position = lrint (font_info->underpos);
890 font->underline_thickness = lrint (font_info->underwidth);
892 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
893 font->props[FONT_FULLNAME_INDEX] =
894 make_unibyte_string (font_info->name, strlen (font_info->name));
902 /* Close FONT on frame F. */
904 nsfont_close (FRAME_PTR f, struct font *font)
906 struct nsfont_info *font_info = (struct nsfont_info *)font;
909 /* FIXME: this occurs apparently due to same failure to detect same font
910 that causes need for cache in nsfont_open () */
914 for (i =0; i<0x100; i++)
916 xfree (font_info->glyphs[i]);
917 xfree (font_info->metrics[i]);
919 [font_info->nsfont release];
921 CGFontRelease (font_info->cgfont);
923 xfree (font_info->name);
928 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
929 return 1. If not, return 0. If a font must be opened to check
932 nsfont_has_char (Lisp_Object entity, int c)
938 /* Return a glyph code of FONT for character C (Unicode code point).
939 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
941 nsfont_encode_char (struct font *font, int c)
943 struct nsfont_info *font_info = (struct nsfont_info *)font;
944 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
948 return FONT_INVALID_CODE;
950 /* did we already cache this block? */
951 if (!font_info->glyphs[high])
952 ns_uni_to_glyphs (font_info, high);
954 g = font_info->glyphs[high][low];
955 return g == 0xFFFF ? FONT_INVALID_CODE : g;
959 /* Perform the size computation of glyphs of FONT and fill in members
960 of METRICS. The glyphs are specified by their glyph codes in
961 CODE (length NGLYPHS). */
963 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
964 struct font_metrics *metrics)
966 struct nsfont_info *font_info = (struct nsfont_info *)font;
967 struct font_metrics *pcm;
968 unsigned char high, low;
972 bzero (metrics, sizeof (struct font_metrics));
974 for (i =0; i<nglyphs; i++)
976 /* get metrics for this glyph, filling cache if need be */
977 /* TODO: get metrics for whole string from an NSLayoutManager
979 high = (code[i] & 0xFF00) >> 8;
980 low = code[i] & 0x00FF;
981 if (!font_info->metrics[high])
982 ns_glyph_metrics (font_info, high);
983 pcm = &(font_info->metrics[high][low]);
985 if (metrics->lbearing > totalWidth + pcm->lbearing)
986 metrics->lbearing = totalWidth + pcm->lbearing;
987 if (metrics->rbearing < totalWidth + pcm->rbearing)
988 metrics->rbearing = totalWidth + pcm->rbearing;
989 if (metrics->ascent < pcm->ascent)
990 metrics->ascent = pcm->ascent;
991 if (metrics->descent < pcm->descent)
992 metrics->descent = pcm->descent;
994 totalWidth += pcm->width;
997 metrics->width = totalWidth;
999 return totalWidth; /* not specified in doc, but xfont.c does it */
1003 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1004 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
1005 is nonzero, fill the background in advance. It is assured that
1006 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1008 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1009 int with_background)
1010 /* NOTE: focus and clip must be set
1011 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1013 static char cbuf[1024];
1015 #ifdef NS_IMPL_GNUSTEP
1016 static float advances[1024];
1017 float *adv = advances;
1019 static CGSize advances[1024];
1020 CGSize *adv = advances;
1024 struct nsfont_info *font = ns_tmp_font;
1025 NSColor *col, *bgCol;
1026 unsigned short *t = s->char2b;
1028 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1029 int end = isComposite ? s->cmp_to : s->nchars;
1031 /* Select face based on input flags */
1032 switch (ns_tmp_flags)
1034 case NS_DUMPGLYPH_CURSOR:
1037 case NS_DUMPGLYPH_MOUSEFACE:
1038 face = FACE_FROM_ID (s->f,
1039 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1041 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1048 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1049 r.origin.x += abs (s->face->box_line_width);
1052 r.size.height = FONT_HEIGHT (font);
1054 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1055 NS to render the string, it will come out differently from the individual
1056 character widths added up because of layout processing. */
1059 int cwidth, twidth = 0;
1061 /* FIXME: composition: no vertical displacement is considered. */
1062 t += s->cmp_from; /* advance into composition */
1063 for (i = s->cmp_from; i < end; i++, t++)
1065 hi = (*t & 0xFF00) >> 8;
1069 if (!s->first_glyph->u.cmp.automatic)
1070 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1073 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1074 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1075 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1076 cwidth = LGLYPH_WIDTH (glyph);
1079 cwidth = LGLYPH_WADJUST (glyph);
1080 #ifdef NS_IMPL_GNUSTEP
1081 *(adv-1) += LGLYPH_XOFF (glyph);
1083 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1090 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1091 ns_glyph_metrics (font, hi);
1092 cwidth = font->metrics[hi][lo].width;
1095 #ifdef NS_IMPL_GNUSTEP
1097 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1099 (*adv++).width = cwidth;
1102 len = adv - advances;
1103 r.size.width = twidth;
1107 /* fill background if requested */
1108 if (with_background && !isComposite)
1111 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1112 int mbox_line_width = max (s->face->box_line_width, 0);
1114 if (s->row->full_width_p)
1116 if (br.origin.x <= fibw + 1 + mbox_line_width)
1118 br.size.width += br.origin.x - mbox_line_width;
1119 br.origin.x = mbox_line_width;
1121 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1123 br.size.width += fibw;
1125 if (s->face->box == FACE_NO_BOX)
1127 /* expand unboxed top row over internal border */
1128 if (br.origin.y <= fibw + 1 + mbox_line_width)
1130 br.size.height += br.origin.y;
1136 int correction = abs (s->face->box_line_width)+1;
1137 br.origin.y += correction;
1138 br.size.height -= 2*correction;
1139 br.origin.x += correction;
1140 br.size.width -= 2*correction;
1143 if (!s->face->stipple)
1144 [(NS_FACE_BACKGROUND (face) != 0
1145 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1146 : FRAME_BACKGROUND_COLOR (s->f)) set];
1149 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1150 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1156 /* set up for character rendering */
1157 r.origin.y += font->voffset + (s->height - font->height)/2;
1159 col = (NS_FACE_FOREGROUND (face) != 0
1160 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1161 : FRAME_FOREGROUND_COLOR (s->f));
1162 /* FIXME: find another way to pass this */
1163 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1164 : (NS_FACE_BACKGROUND (face) != 0
1165 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1166 : FRAME_BACKGROUND_COLOR (s->f)));
1168 /* render under GNUstep using DPS */
1169 #ifdef NS_IMPL_GNUSTEP
1171 NSGraphicsContext *context = GSCurrentContext ();
1176 /* do erase if "foreground" mode */
1180 DPSmoveto (context, r.origin.x, r.origin.y);
1181 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1182 DPSxshow (context, cbuf, advances, len);
1183 DPSstroke (context);
1185 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1189 if (face->underline_p)
1191 if (face->underline_color != 0)
1192 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1195 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1196 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1197 if (face->underline_color != 0)
1203 /* draw with DPSxshow () */
1204 DPSmoveto (context, r.origin.x, r.origin.y);
1205 DPSxshow (context, cbuf, advances, len);
1206 DPSstroke (context);
1208 DPSgrestore (context);
1212 #else /* NS_IMPL_COCOA */
1214 CGContextRef gcontext =
1215 [[NSGraphicsContext currentContext] graphicsPort];
1216 static CGAffineTransform fliptf;
1217 static BOOL firstTime = YES;
1222 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1225 CGContextSaveGState (gcontext);
1227 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1229 CGContextSetFont (gcontext, font->cgfont);
1230 CGContextSetFontSize (gcontext, font->size);
1231 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1232 CGContextSetShouldAntialias (gcontext, 0);
1234 CGContextSetShouldAntialias (gcontext, 1);
1236 CGContextSetTextMatrix (gcontext, fliptf);
1240 /* foreground drawing; erase first to avoid overstrike */
1242 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1243 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1244 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1245 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1248 if (face->underline_p)
1250 if (face->underline_color != 0)
1251 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1254 CGContextBeginPath (gcontext);
1255 CGContextMoveToPoint (gcontext,
1256 r.origin.x, r.origin.y + font->underpos);
1257 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1258 r.origin.y + font->underpos);
1259 CGContextStrokePath (gcontext);
1260 if (face->underline_color != 0)
1266 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1267 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1270 if (face->overstrike)
1272 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1273 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1277 CGContextRestoreGState (gcontext);
1280 #endif /* NS_IMPL_COCOA */
1286 /* ==========================================================================
1288 Font glyph and metrics caching functions
1290 ========================================================================== */
1292 /* Find and cache corresponding glyph codes for unicode values in given
1293 hi-byte block of 256. */
1295 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1297 #ifdef NS_IMPL_COCOA
1298 static EmacsGlyphStorage *glyphStorage;
1299 static char firstTime = 1;
1301 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1302 unsigned int i, g, idx;
1303 unsigned short *glyphs;
1306 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1311 #ifdef NS_IMPL_COCOA
1315 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1319 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1320 if (!unichars || !(font_info->glyphs[block]))
1323 /* create a string containing all unicode characters in this block */
1324 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1325 if (idx < 0xD800 || idx > 0xDFFF)
1328 unichars[i] = 0xFEFF;
1329 unichars[0x100] = 0;
1332 #ifdef NS_IMPL_COCOA
1333 NSString *allChars = [[NSString alloc]
1334 initWithCharactersNoCopy: unichars
1337 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1338 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1339 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1340 NSUInteger gInd =0, cInd =0;
1342 [glyphStorage setString: allChars font: font_info->nsfont];
1343 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1344 desiredNumberOfCharacters: glyphStorage->maxChar
1345 glyphIndex: &gInd characterIndex: &cInd];
1347 glyphs = font_info->glyphs[block];
1348 for (i =0; i<0x100; i++, glyphs++)
1350 #ifdef NS_IMPL_GNUSTEP
1353 g = glyphStorage->cglyphs[i];
1354 /* TODO: is this a good check? maybe need to use coveredChars.. */
1356 g = 0xFFFF; /* hopefully unused... */
1361 #ifdef NS_IMPL_COCOA
1371 /* Determine and cache metrics for corresponding glyph codes in given
1372 hi-byte block of 256. */
1374 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1377 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1379 struct font_metrics *metrics;
1382 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1385 #ifdef NS_IMPL_GNUSTEP
1386 /* not implemented yet (as of startup 0.18), so punt */
1388 numGlyphs = 0x10000;
1392 sfont = [font_info->nsfont screenFont];
1394 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1395 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1396 if (!(font_info->metrics[block]))
1399 metrics = font_info->metrics[block];
1400 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1403 NSRect r = [sfont boundingRectForGlyph: g];
1405 w = max ([sfont advancementForGlyph: g].width, 2.0);
1406 metrics->width = lrint (w);
1409 rb = r.size.width - w;
1411 metrics->lbearing = round (lb);
1412 if (font_info->ital)
1413 rb += 0.22 * font_info->height;
1414 metrics->rbearing = lrint (w + rb);
1416 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1417 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1418 metrics->ascent = r.size.height - metrics->descent;
1419 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1425 #ifdef NS_IMPL_COCOA
1426 /* helper for font glyph setup */
1427 @implementation EmacsGlyphStorage
1431 return [self initWithCapacity: 1024];
1434 - initWithCapacity: (unsigned long) c
1436 self = [super init];
1439 dict = [NSMutableDictionary new];
1440 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1453 - (void) setString: (NSString *)str font: (NSFont *)font
1455 [dict setObject: font forKey: NSFontAttributeName];
1456 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1457 maxChar = [str length];
1461 /* NSGlyphStorage protocol */
1462 - (NSUInteger)layoutOptions
1467 - (NSAttributedString *)attributedString
1472 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1473 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1474 characterIndex: (NSUInteger)charIndex
1476 len = glyphIndex+length;
1477 for (i =glyphIndex; i<len; i++)
1478 cglyphs[i] = glyphs[i-glyphIndex];
1483 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1484 forGlyphAtIndex: (NSUInteger)glyphIndex
1490 #endif /* NS_IMPL_COCOA */
1495 ns_dump_glyphstring (struct glyph_string *s)
1499 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1500 "overlap = %d, bg_filled = %d:",
1501 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1502 s->row->overlapping_p, s->background_filled_p);
1503 for (i =0; i<s->nchars; i++)
1504 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1505 fprintf (stderr, "\n");
1512 nsfont_driver.type = Qns;
1513 register_font_driver (&nsfont_driver, NULL);
1514 DEFSYM (Qapple, "apple");
1515 DEFSYM (Qroman, "roman");
1516 DEFSYM (Qmedium, "medium");
1517 DEFVAR_LISP ("ns-reg-to-script", &Vns_reg_to_script,
1518 doc: /* Internal use: maps font registry to unicode script. */);
1521 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae