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 /* This header is not included from GNUstep's (0.16.0) AppKit.h. */
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 Qapple, Qroman, Qmedium;
50 extern Lisp_Object Qappend;
51 extern int ns_antialias_text, ns_use_qd_smoothing;
52 extern float ns_antialias_threshold;
53 extern int ns_tmp_flags;
54 extern struct nsfont_info *ns_tmp_font;
56 /* font glyph and metrics caching functions, implemented at end */
57 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
59 static void ns_glyph_metrics (struct nsfont_info *font_info,
63 /* ==========================================================================
67 ========================================================================== */
70 /* Replace spaces w/another character so emacs core font parsing routines
73 ns_escape_name (char *name)
75 int i =0, len =strlen (name);
82 /* Reconstruct spaces in a font family name passed through emacs. */
84 ns_unescape_name (char *name)
86 int i =0, len =strlen (name);
93 /* Extract family name from a font spec. */
95 ns_get_family (Lisp_Object font_spec)
97 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
102 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
104 ns_unescape_name (tmp);
105 /* For names hard-coded into emacs, like 'helvetica' for splash. */
106 tmp[0] = toupper (tmp[0]);
107 family = [NSString stringWithUTF8String: tmp];
114 /* Return 0 if attr not set, else value (which might also be 0).
115 On Leopard 0 gets returned even on descriptors where the attribute
116 was never set, so there's no way to distinguish between unspecified
117 and set to not have. Callers should assume 0 means unspecified. */
119 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
121 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
122 NSNumber *val = [tdict objectForKey: trait];
123 return val == nil ? 0.0 : [val floatValue];
127 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
128 to NSFont descriptor. Information under extra only needed for matching. */
129 #define STYLE_REF 100
130 static NSFontDescriptor
131 *ns_spec_to_descriptor(Lisp_Object font_spec)
133 NSFontDescriptor *fdesc;
134 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
135 NSMutableDictionary *tdict = [NSMutableDictionary new];
136 NSString *family = ns_get_family (font_spec);
139 /* add each attr in font_spec to fdAttrs.. */
140 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
141 if (n != -1 && n != STYLE_REF)
142 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
143 forKey: NSFontWeightTrait];
144 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
145 if (n != -1 && n != STYLE_REF)
146 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
147 forKey: NSFontSlantTrait];
148 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
149 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
150 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
151 forKey: NSFontWidthTrait];
152 if ([tdict count] > 0)
153 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
155 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
157 fdesc = [fdesc fontDescriptorWithFamily: family];
162 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
164 ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
166 Lisp_Object font_entity = font_make_entity ();
167 /* NSString *psName = [desc postscriptName]; */
168 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
169 char *escapedFamily = strdup ([family UTF8String]);
170 unsigned int traits = [desc symbolicTraits];
172 ns_escape_name (escapedFamily);
174 ASET (font_entity, FONT_TYPE_INDEX, Qns);
175 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
176 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
177 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
178 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
180 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
181 traits & NSFontBoldTrait ? Qbold : Qmedium);
182 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
183 make_number (100 + 100
184 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
185 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
186 traits & NSFontItalicTrait ? Qitalic : Qnormal);
187 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
188 make_number (100 + 100
189 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
190 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
191 traits & NSFontCondensedTrait ? Qcondensed :
192 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
193 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
194 make_number (100 + 100
195 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
197 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
198 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
199 ASET (font_entity, FONT_SPACING_INDEX,
200 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
201 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
203 ASET (font_entity, FONT_EXTRA_INDEX, extra);
204 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
208 fprintf (stderr, "created font_entity:\n ");
209 debug_print (font_entity);
212 free (escapedFamily);
217 /* Default font entity. */
219 ns_fallback_entity ()
221 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
222 fontDescriptor], Qnil, NULL);
226 /* Utility: get width of a char c in screen font sfont */
228 ns_char_width (NSFont *sfont, int c)
231 NSString *cstr = [NSString stringWithFormat: @"%c", c];
233 NSGlyph glyph = [sfont glyphWithName: cstr];
236 float w = [sfont advancementForGlyph: glyph].width;
241 w = [sfont widthOfString: cstr];
246 /* Return whether set1 covers set2 to a reasonable extent given by pct.
247 We check, out of each 16 unicode char range containing chars in set2,
248 whether at least one character is present in set1.
249 This must be true for pct of the pairs to consider it covering. */
251 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
253 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
254 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
255 int i, off = 0, tot = 0;
257 for (i=0; i<4096; i++, bytes1++, bytes2++)
261 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
264 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
265 return (float)off / tot < 1.0 - pct;
269 /* Convert :lang property to a script. Use of :lang property by font backend
270 seems to be limited for now (2009/05) to ja, zh, and ko. */
272 *ns_lang_to_script (Lisp_Object lang)
274 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
276 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
277 have more characters. */
278 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
280 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
287 /* Convert OTF 4-letter script code to emacs script name. (Why can't
288 everyone just use some standard unicode names for these?) */
290 *ns_otf_to_script (Lisp_Object otf)
292 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
293 return CONSP (script)
294 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
299 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec
300 for something that can be mapped to a unicode script. Empty string returned
301 if no script spec found.
302 TODO: Eventually registry / encoding should be checked and mapped, but for
303 now the font backend will try script/lang/otf if registry fails, so it is
306 *ns_get_req_script (Lisp_Object font_spec)
308 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
310 for ( ; CONSP (extra); extra = XCDR (extra))
312 Lisp_Object tmp = XCAR (extra);
315 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
316 if (EQ (key, QCscript) && SYMBOLP (val))
317 return [NSString stringWithUTF8String:
318 SDATA (SYMBOL_NAME (val))];
319 if (EQ (key, QClang) && SYMBOLP (val))
320 return ns_lang_to_script (val);
321 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
322 return ns_otf_to_script (val);
329 /* This small function is static in fontset.c. If it can be made public for
330 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
332 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
334 if (EQ (XCAR (arg), val))
337 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
339 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
344 /* Use the unicode range information in Vchar_script_table to convert a script
345 name into an NSCharacterSet. */
346 static NSCharacterSet
347 *ns_script_to_charset (NSString *scriptName)
349 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
350 Lisp_Object script = intern ([scriptName UTF8String]);
351 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
353 if (! NILP (Fmemq (script, script_list)))
355 Lisp_Object ranges, range_list;
357 ranges = Fcons (script, Qnil);
358 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
360 range_list = Fnreverse (XCDR (ranges));
361 if (! NILP (range_list))
363 for (; CONSP (range_list); range_list = XCDR (range_list))
365 int start = XINT (XCAR (XCAR (range_list)));
366 int end = XINT (XCDR (XCAR (range_list)));
368 debug_print (XCAR (range_list));
370 [charset addCharactersInRange:
371 NSMakeRange (start, end-start)];
379 /* Return an array of font families containing characters for the given
380 script, for the given coverage criterion, including at least LastResort.
381 Results are cached by script for faster access.
382 If none are found, we reduce the percentage and try again, until 5%.
383 This provides a font with at least some characters if such can be found.
384 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
385 (b) need approximate match as fonts covering full unicode ranges are rare. */
387 *ns_get_covering_families (NSString *script, float pct)
389 static NSMutableDictionary *scriptToFamilies = nil;
390 NSMutableSet *families;
393 NSLog(@"Request covering families for script: '%@'", script);
395 if (scriptToFamilies == nil)
396 scriptToFamilies = [[NSMutableDictionary alloc] init];
398 if ((families = [scriptToFamilies objectForKey: script]) == nil)
400 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
401 NSArray *allFamilies = [fontMgr availableFontFamilies];
403 if ([script length] == 0)
404 families = [NSMutableSet setWithArray: allFamilies];
407 NSCharacterSet *charset = ns_script_to_charset (script);
409 families = [NSMutableSet setWithCapacity: 10];
412 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
413 while (family = [allFamiliesEnum nextObject])
415 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
416 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
417 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
419 fset = [NSCharacterSet characterSetWithRange:
420 NSMakeRange (0, 127)];
421 if (ns_charset_covers(fset, charset, pct))
422 [families addObject: family];
425 if ([families count] > 0 || pct < 0.05)
430 if ([families count] == 0)
431 [families addObject: @"LastResort"];
433 [scriptToFamilies setObject: families forKey: script];
437 NSLog(@" returning %d families", [families count]);
442 /* Implementation for list() and match(). List() can return nil, match()
443 must return something. Strategy is to drop family name from attribute
444 matching set for match. */
446 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
448 Lisp_Object tem, list = Qnil;
449 NSFontDescriptor *fdesc, *desc;
451 NSArray *matchingDescs;
459 fprintf (stderr, "nsfont: %s for fontspec:\n ",
460 (isMatch ? "match" : "list"));
461 debug_print (font_spec);
464 /* If has non-unicode registry, give up. */
465 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
466 if (! NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
467 return isMatch ? Fcons (ns_fallback_entity (), list) : Qnil;
469 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
471 fdesc = ns_spec_to_descriptor (font_spec);
472 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
474 [fkeys removeObject: NSFontFamilyAttribute];
476 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
478 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
479 [matchingDescs count]);
481 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
483 if (![cFamilies containsObject:
484 [desc objectForKey: NSFontFamilyAttribute]])
486 list = Fcons (ns_descriptor_to_entity (desc,
487 AREF (font_spec, FONT_EXTRA_INDEX),
489 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
493 /* Add synthItal member if needed. */
494 family = [fdesc objectForKey: NSFontFamilyAttribute];
495 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
497 NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
498 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
499 fontDescriptorWithFamily: family];
500 list = Fcons (ns_descriptor_to_entity (sDesc,
501 AREF (font_spec, FONT_EXTRA_INDEX),
505 /* Return something if was a match and nothing found. */
506 if (isMatch && XINT (Flength (list)) == 0)
507 list = Fcons (ns_fallback_entity (), Qnil);
510 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
517 /* ==========================================================================
519 Font driver implementation
521 ========================================================================== */
524 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
525 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
526 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
527 static Lisp_Object nsfont_list_family (Lisp_Object frame);
528 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
530 static void nsfont_close (FRAME_PTR f, struct font *font);
531 static int nsfont_has_char (Lisp_Object entity, int c);
532 static unsigned int nsfont_encode_char (struct font *font, int c);
533 static int nsfont_text_extents (struct font *font, unsigned int *code,
534 int nglyphs, struct font_metrics *metrics);
535 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
536 int with_background);
538 struct font_driver nsfont_driver =
541 1, /* case sensitive */
546 NULL, /*free_entity */
549 NULL, /* prepare_face */
550 NULL, /* done_face */
555 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
556 anchor_point, otf_capability, otf_driver,
557 start_for_frame, end_for_frame, shape */
561 /* Return a cache of font-entities on FRAME. The cache must be a
562 cons whose cdr part is the actual cache area. */
564 nsfont_get_cache (FRAME_PTR frame)
566 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
567 return (dpyinfo->name_list_element);
571 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
572 **list** of font-entities. This and match () are sole APIs that allocate
573 font-entities. Properties to be considered (2009/05/19) are:
574 regular: foundry, family, adstyle, registry
575 extended: script, lang, otf
576 "Extended" properties are not part of the vector but get stored as
577 lisp properties under FONT_EXTRA_INDEX.
579 The returned entities should have type set (to 'ns), plus the following:
580 foundry, family, adstyle, registry,
581 weight, slant, width, size (0 if scalable),
582 dpi, spacing, avgwidth (0 if scalable) */
584 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
586 return ns_findfonts (font_spec, NO);
590 /* Return a font entity most closely maching with FONT_SPEC on
591 FRAME. The closeness is determined by the font backend, thus
592 `face-font-selection-order' is ignored here.
593 Properties to be considered are same as for list(). */
595 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
597 return ns_findfonts(font_spec, YES);
601 /* List available families. The value is a list of family names
604 nsfont_list_family (Lisp_Object frame)
606 Lisp_Object list = Qnil;
607 NSEnumerator *families =
608 [[[NSFontManager sharedFontManager] availableFontFamilies]
611 while (family = [families nextObject])
612 list = Fcons (intern ([family UTF8String]), list);
613 /* FIXME: escape the name? */
616 fprintf (stderr, "nsfont: list families returning %d entries\n",
617 XINT (Flength (list)));
623 /* Open a font specified by FONT_ENTITY on frame F. If the font is
624 scalable, open it with PIXEL_SIZE. */
626 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
629 unsigned int traits = 0;
630 struct nsfont_info *font_info;
632 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
633 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
635 NSFont *nsfont, *sfont;
638 Lisp_Object font_object;
641 static NSMutableDictionary *fontCache = nil;
644 /* 2008/03/08: The same font may end up being requested for different
645 entities, due to small differences in numeric values or other issues,
646 or for different copies of the same entity. Therefore we cache to
647 avoid creating multiple struct font objects (with metrics cache, etc.)
648 for the same NSFont object. */
649 if (fontCache == nil)
650 fontCache = [[NSMutableDictionary alloc] init];
654 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
655 debug_print (font_entity);
660 /* try to get it out of frame params */
661 Lisp_Object tem = get_frame_param (f, Qfontsize);
662 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
665 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
666 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
668 family = ns_get_family (font_entity);
669 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
670 when setting family in ns_spec_to_descriptor(). */
671 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
672 traits |= NSBoldFontMask;
673 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
674 traits |= NSItalicFontMask;
676 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
677 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
678 nsfont = [fontMgr fontWithFamily: family
679 traits: traits weight: fixLeopardBug
681 /* if didn't find, try synthetic italic */
682 if (nsfont == nil && synthItal)
684 nsfont = [fontMgr fontWithFamily: family
685 traits: traits & ~NSItalicFontMask
686 weight: fixLeopardBug size: pixel_size];
689 /* LastResort not really a family */
690 if (nsfont == nil && [@"LastResort" isEqualToString: family])
691 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
696 message_with_string ("*** Warning: font in family '%s' not found",
697 build_string ([family UTF8String]), 1);
698 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
702 NSLog (@"%@\n", nsfont);
704 /* Check the cache */
705 cached = [fontCache objectForKey: nsfont];
706 if (cached != nil && !synthItal)
709 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
710 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
711 XHASH (font_object) = [cached unsignedLongValue];
716 font_object = font_make_object (VECSIZE (struct nsfont_info),
717 font_entity, pixel_size);
719 [fontCache setObject: [NSNumber numberWithUnsignedLong:
720 (unsigned long) XHASH (font_object)]
724 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
725 font = (struct font *) font_info;
727 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
729 font_info->glyphs = (unsigned short **)
730 xmalloc (0x100 * sizeof (unsigned short *));
731 font_info->metrics = (struct font_metrics **)
732 xmalloc (0x100 * sizeof (struct font_metrics *));
733 if (!font_info->glyphs || !font_info->metrics)
735 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
736 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
741 sfont = [nsfont screenFont];
745 /* non-metric backend font struct fields */
746 font = (struct font *) font_info;
747 font->pixel_size = [sfont pointSize];
748 font->driver = &nsfont_driver;
749 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
750 font->encoding_charset = -1;
751 font->repertory_charset = -1;
752 font->default_ascent = 0;
753 font->vertical_centering = 0;
754 font->baseline_offset = 0;
755 font->relative_compose = 0;
756 font->font_encoder = NULL;
758 font->props[FONT_FORMAT_INDEX] = Qns;
759 font->props[FONT_FILE_INDEX] = Qnil;
762 double expand, hshrink;
763 float full_height, min_height, hd;
764 const char *fontName = [[nsfont fontName] UTF8String];
765 int len = strlen (fontName);
767 #ifdef NS_IMPL_GNUSTEP
768 font_info->nsfont = sfont;
770 font_info->nsfont = nsfont;
772 [font_info->nsfont retain];
774 /* set up ns_font (defined in nsgui.h) */
775 font_info->name = (char *)xmalloc (strlen (fontName) + 1);
776 bcopy (fontName, font_info->name, strlen (fontName) + 1);
777 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
779 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
781 /* Metrics etc.; some fonts return an unusually large max advance, so we
782 only use it for fonts that have wide characters. */
783 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
784 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
786 brect = [sfont boundingRectForFont];
787 full_height = brect.size.height;
788 min_height = [sfont ascender] - [sfont descender];
789 hd = full_height - min_height;
791 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
795 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
796 font_info->underwidth = [sfont underlineThickness];
797 font_info->size = font->pixel_size;
798 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
801 font_info->max_bounds.ascent =
802 lrint (hshrink * [sfont ascender] + expand * hd/2);
803 font_info->max_bounds.descent =
804 -lrint (hshrink* [sfont descender] - expand*hd/2);
806 font_info->max_bounds.ascent + font_info->max_bounds.descent;
807 font_info->max_bounds.width = lrint (font_info->width);
808 font_info->max_bounds.lbearing = lrint (brect.origin.x);
809 font_info->max_bounds.rbearing =
810 lrint (brect.size.width - font_info->width);
813 /* set up synthItal and the CG font */
814 font_info->synthItal = synthItal;
816 ATSFontRef atsFont = ATSFontFindFromPostScriptName
817 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
819 if (atsFont == kATSFontRefUnspecified)
821 /* see if we can get it by dropping italic (then synthesizing) */
822 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
823 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
824 fontName], kATSOptionFlagsDefault);
825 if (atsFont != kATSFontRefUnspecified)
826 font_info->synthItal = YES;
829 /* last resort fallback */
830 atsFont = ATSFontFindFromPostScriptName
831 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
834 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
838 /* set up metrics portion of font struct */
839 font->ascent = [sfont ascender];
840 font->descent = -[sfont descender];
841 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
842 font->space_width = lrint (ns_char_width (sfont, ' '));
843 font->average_width = lrint (font_info->width);
844 font->max_width = lrint (font_info->max_bounds.width);
845 font->height = lrint (font_info->height);
846 font->underline_position = lrint (font_info->underpos);
847 font->underline_thickness = lrint (font_info->underwidth);
849 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
850 font->props[FONT_FULLNAME_INDEX] =
851 make_unibyte_string (font_info->name, strlen (font_info->name));
859 /* Close FONT on frame F. */
861 nsfont_close (FRAME_PTR f, struct font *font)
863 struct nsfont_info *font_info = (struct nsfont_info *)font;
866 /* FIXME: this occurs apparently due to same failure to detect same font
867 that causes need for cache in nsfont_open () */
871 for (i =0; i<0x100; i++)
873 xfree (font_info->glyphs[i]);
874 xfree (font_info->metrics[i]);
876 [font_info->nsfont release];
878 CGFontRelease (font_info->cgfont);
880 xfree (font_info->name);
885 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
886 return 1. If not, return 0. If a font must be opened to check
889 nsfont_has_char (Lisp_Object entity, int c)
895 /* Return a glyph code of FONT for character C (Unicode code point).
896 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
898 nsfont_encode_char (struct font *font, int c)
900 struct nsfont_info *font_info = (struct nsfont_info *)font;
901 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
905 return FONT_INVALID_CODE;
907 /* did we already cache this block? */
908 if (!font_info->glyphs[high])
909 ns_uni_to_glyphs (font_info, high);
911 g = font_info->glyphs[high][low];
912 return g == 0xFFFF ? FONT_INVALID_CODE : g;
916 /* Perform the size computation of glyphs of FONT and fill in members
917 of METRICS. The glyphs are specified by their glyph codes in
918 CODE (length NGLYPHS). */
920 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
921 struct font_metrics *metrics)
923 struct nsfont_info *font_info = (struct nsfont_info *)font;
924 struct font_metrics *pcm;
925 unsigned char high, low;
929 bzero (metrics, sizeof (struct font_metrics));
931 for (i =0; i<nglyphs; i++)
933 /* get metrics for this glyph, filling cache if need be */
934 /* TODO: get metrics for whole string from an NSLayoutManager
936 high = (code[i] & 0xFF00) >> 8;
937 low = code[i] & 0x00FF;
938 if (!font_info->metrics[high])
939 ns_glyph_metrics (font_info, high);
940 pcm = &(font_info->metrics[high][low]);
942 if (metrics->lbearing > totalWidth + pcm->lbearing)
943 metrics->lbearing = totalWidth + pcm->lbearing;
944 if (metrics->rbearing < totalWidth + pcm->rbearing)
945 metrics->rbearing = totalWidth + pcm->rbearing;
946 if (metrics->ascent < pcm->ascent)
947 metrics->ascent = pcm->ascent;
948 if (metrics->descent < pcm->descent)
949 metrics->descent = pcm->descent;
951 totalWidth += pcm->width;
954 metrics->width = totalWidth;
956 return totalWidth; /* not specified in doc, but xfont.c does it */
960 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
961 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
962 is nonzero, fill the background in advance. It is assured that
963 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
965 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
967 /* NOTE: focus and clip must be set
968 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
970 static char cbuf[1024];
972 #ifdef NS_IMPL_GNUSTEP
973 static float advances[1024];
974 float *adv = advances;
976 static CGSize advances[1024];
977 CGSize *adv = advances;
981 struct nsfont_info *font = ns_tmp_font;
982 NSColor *col, *bgCol;
983 unsigned short *t = s->char2b;
985 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
986 int end = isComposite ? s->cmp_to : s->nchars;
988 /* Select face based on input flags */
989 switch (ns_tmp_flags)
991 case NS_DUMPGLYPH_CURSOR:
994 case NS_DUMPGLYPH_MOUSEFACE:
995 face = FACE_FROM_ID (s->f,
996 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
998 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1005 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1006 r.origin.x += abs (s->face->box_line_width);
1009 r.size.height = FONT_HEIGHT (font);
1011 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1012 NS to render the string, it will come out differently from the individual
1013 character widths added up because of layout processing. */
1016 int cwidth, twidth = 0;
1018 /* FIXME: composition: no vertical displacement is considered. */
1019 t += s->cmp_from; /* advance into composition */
1020 for (i = s->cmp_from; i < end; i++, t++)
1022 hi = (*t & 0xFF00) >> 8;
1026 if (!s->first_glyph->u.cmp.automatic)
1027 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1030 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1031 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1032 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1033 cwidth = LGLYPH_WIDTH (glyph);
1036 cwidth = LGLYPH_WADJUST (glyph);
1037 #ifdef NS_IMPL_GNUSTEP
1038 *(adv-1) += LGLYPH_XOFF (glyph);
1040 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1047 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1048 ns_glyph_metrics (font, hi);
1049 cwidth = font->metrics[hi][lo].width;
1052 #ifdef NS_IMPL_GNUSTEP
1054 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1056 (*adv++).width = cwidth;
1059 len = adv - advances;
1060 r.size.width = twidth;
1064 /* fill background if requested */
1065 if (with_background && !isComposite)
1068 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1069 int mbox_line_width = max (s->face->box_line_width, 0);
1071 if (s->row->full_width_p)
1073 if (br.origin.x <= fibw + 1 + mbox_line_width)
1075 br.size.width += br.origin.x - mbox_line_width;
1076 br.origin.x = mbox_line_width;
1078 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1080 br.size.width += fibw;
1082 if (s->face->box == FACE_NO_BOX)
1084 /* expand unboxed top row over internal border */
1085 if (br.origin.y <= fibw + 1 + mbox_line_width)
1087 br.size.height += br.origin.y;
1093 int correction = abs (s->face->box_line_width)+1;
1094 br.origin.y += correction;
1095 br.size.height -= 2*correction;
1096 br.origin.x += correction;
1097 br.size.width -= 2*correction;
1100 if (!s->face->stipple)
1101 [(NS_FACE_BACKGROUND (face) != 0
1102 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1103 : FRAME_BACKGROUND_COLOR (s->f)) set];
1106 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1107 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1113 /* set up for character rendering */
1114 r.origin.y += font->voffset + (s->height - font->height)/2;
1116 col = (NS_FACE_FOREGROUND (face) != 0
1117 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1118 : FRAME_FOREGROUND_COLOR (s->f));
1119 /* FIXME: find another way to pass this */
1120 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1121 : (NS_FACE_BACKGROUND (face) != 0
1122 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1123 : FRAME_BACKGROUND_COLOR (s->f)));
1125 /* render under GNUstep using DPS */
1126 #ifdef NS_IMPL_GNUSTEP
1128 NSGraphicsContext *context = GSCurrentContext ();
1133 /* do erase if "foreground" mode */
1137 DPSmoveto (context, r.origin.x, r.origin.y);
1138 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1139 DPSxshow (context, cbuf, advances, len);
1140 DPSstroke (context);
1142 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1146 if (face->underline_p)
1148 if (face->underline_color != 0)
1149 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1152 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1153 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1154 if (face->underline_color != 0)
1160 /* draw with DPSxshow () */
1161 DPSmoveto (context, r.origin.x, r.origin.y);
1162 DPSxshow (context, cbuf, advances, len);
1163 DPSstroke (context);
1165 DPSgrestore (context);
1169 #else /* NS_IMPL_COCOA */
1171 CGContextRef gcontext =
1172 [[NSGraphicsContext currentContext] graphicsPort];
1173 static CGAffineTransform fliptf;
1174 static BOOL firstTime = YES;
1179 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1182 CGContextSaveGState (gcontext);
1184 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1186 CGContextSetFont (gcontext, font->cgfont);
1187 CGContextSetFontSize (gcontext, font->size);
1188 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1189 CGContextSetShouldAntialias (gcontext, 0);
1191 CGContextSetShouldAntialias (gcontext, 1);
1192 if (EQ (ns_use_qd_smoothing, Qt))
1193 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1195 CGContextSetTextMatrix (gcontext, fliptf);
1199 /* foreground drawing; erase first to avoid overstrike */
1201 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1202 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1203 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1204 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1207 if (face->underline_p)
1209 if (face->underline_color != 0)
1210 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1213 CGContextBeginPath (gcontext);
1214 CGContextMoveToPoint (gcontext,
1215 r.origin.x, r.origin.y + font->underpos);
1216 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1217 r.origin.y + font->underpos);
1218 CGContextStrokePath (gcontext);
1219 if (face->underline_color != 0)
1225 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1226 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1229 if (face->overstrike)
1231 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1232 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1236 CGContextRestoreGState (gcontext);
1239 #endif /* NS_IMPL_COCOA */
1245 /* ==========================================================================
1247 Font glyph and metrics caching functions
1249 ========================================================================== */
1251 /* Find and cache corresponding glyph codes for unicode values in given
1252 hi-byte block of 256. */
1254 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1256 #ifdef NS_IMPL_COCOA
1257 static EmacsGlyphStorage *glyphStorage;
1258 static char firstTime = 1;
1260 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1261 unsigned int i, g, idx;
1262 unsigned short *glyphs;
1265 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1270 #ifdef NS_IMPL_COCOA
1274 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1278 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1279 if (!unichars || !(font_info->glyphs[block]))
1282 /* create a string containing all unicode characters in this block */
1283 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1284 if (idx < 0xD800 || idx > 0xDFFF)
1287 unichars[i] = 0xFEFF;
1288 unichars[0x100] = 0;
1291 #ifdef NS_IMPL_COCOA
1292 NSString *allChars = [[NSString alloc]
1293 initWithCharactersNoCopy: unichars
1296 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1297 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1298 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1299 unsigned int gInd =0, cInd =0;
1301 [glyphStorage setString: allChars font: font_info->nsfont];
1302 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1303 desiredNumberOfCharacters: glyphStorage->maxChar
1304 glyphIndex: &gInd characterIndex: &cInd];
1306 glyphs = font_info->glyphs[block];
1307 for (i =0; i<0x100; i++, glyphs++)
1309 #ifdef NS_IMPL_GNUSTEP
1312 g = glyphStorage->cglyphs[i];
1313 /* TODO: is this a good check? maybe need to use coveredChars.. */
1315 g = 0xFFFF; /* hopefully unused... */
1320 #ifdef NS_IMPL_COCOA
1330 /* Determine and cache metrics for corresponding glyph codes in given
1331 hi-byte block of 256. */
1333 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1336 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1338 struct font_metrics *metrics;
1341 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1344 #ifdef NS_IMPL_GNUSTEP
1345 /* not implemented yet (as of startup 0.18), so punt */
1347 numGlyphs = 0x10000;
1351 sfont = [font_info->nsfont screenFont];
1353 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1354 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1355 if (!(font_info->metrics[block]))
1358 metrics = font_info->metrics[block];
1359 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1362 NSRect r = [sfont boundingRectForGlyph: g];
1364 #ifdef NS_IMPL_GNUSTEP
1367 NSString *s = [NSString stringWithFormat: @"%c", g];
1368 w = [sfont widthOfString: s];
1371 w = [sfont advancementForGlyph: g].width;
1374 metrics->width = lrint (w);
1377 rb = r.size.width - w;
1379 metrics->lbearing = round (lb);
1380 if (font_info->ital)
1381 rb += 0.22 * font_info->height;
1382 metrics->rbearing = lrint (w + rb);
1384 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1385 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1386 metrics->ascent = r.size.height - metrics->descent;
1387 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1393 #ifdef NS_IMPL_COCOA
1394 /* helper for font glyph setup */
1395 @implementation EmacsGlyphStorage
1399 return [self initWithCapacity: 1024];
1402 - initWithCapacity: (unsigned long) c
1404 self = [super init];
1407 dict = [NSMutableDictionary new];
1408 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1421 - (void) setString: (NSString *)str font: (NSFont *)font
1423 [dict setObject: font forKey: NSFontAttributeName];
1424 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1425 maxChar = [str length];
1429 /* NSGlyphStorage protocol */
1430 - (unsigned int)layoutOptions
1435 - (NSAttributedString *)attributedString
1440 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1441 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1442 characterIndex: (unsigned int)charIndex
1444 len = glyphIndex+length;
1445 for (i =glyphIndex; i<len; i++)
1446 cglyphs[i] = glyphs[i-glyphIndex];
1451 - (void)setIntAttribute: (int)attributeTag value: (int)val
1452 forGlyphAtIndex: (unsigned)glyphIndex
1458 #endif /* NS_IMPL_COCOA */
1463 ns_dump_glyphstring (struct glyph_string *s)
1467 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1468 "overlap = %d, bg_filled = %d:",
1469 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1470 s->row->overlapping_p, s->background_filled_p);
1471 for (i =0; i<s->nchars; i++)
1472 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1473 fprintf (stderr, "\n");
1480 nsfont_driver.type = Qns;
1481 register_font_driver (&nsfont_driver, NULL);
1482 DEFSYM (Qapple, "apple");
1483 DEFSYM (Qroman, "roman");
1484 DEFSYM (Qmedium, "medium");
1487 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae