1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010 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. */
29 #include "dispextern.h"
30 #include "composite.h"
31 #include "blockinput.h"
38 #include "character.h"
41 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
42 #ifdef NS_IMPL_GNUSTEP
43 #import <AppKit/NSFontDescriptor.h>
46 #define NSFONT_TRACE 0
48 extern Lisp_Object Qns;
49 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
50 static Lisp_Object Vns_reg_to_script;
51 static Lisp_Object Qapple, Qroman, Qmedium;
52 extern Lisp_Object Qappend;
53 extern Lisp_Object ns_antialias_text;
54 extern float ns_antialias_threshold;
55 extern int ns_tmp_flags;
56 extern struct nsfont_info *ns_tmp_font;
58 /* font glyph and metrics caching functions, implemented at end */
59 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
61 static void ns_glyph_metrics (struct nsfont_info *font_info,
65 /* ==========================================================================
69 ========================================================================== */
72 /* Replace spaces w/another character so emacs core font parsing routines
75 ns_escape_name (char *name)
77 int i =0, len =strlen (name);
84 /* Reconstruct spaces in a font family name passed through emacs. */
86 ns_unescape_name (char *name)
88 int i =0, len =strlen (name);
95 /* Extract family name from a font spec. */
97 ns_get_family (Lisp_Object font_spec)
99 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
104 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
106 ns_unescape_name (tmp);
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 unsigned int traits = [desc symbolicTraits];
172 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
174 family = [desc objectForKey: NSFontNameAttribute];
176 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
178 escapedFamily = strdup ([family UTF8String]);
179 ns_escape_name (escapedFamily);
181 ASET (font_entity, FONT_TYPE_INDEX, Qns);
182 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
183 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
184 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
185 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
187 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
188 traits & NSFontBoldTrait ? Qbold : Qmedium);
189 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
190 make_number (100 + 100
191 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
192 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
193 traits & NSFontItalicTrait ? Qitalic : Qnormal);
194 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
195 make_number (100 + 100
196 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
197 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
198 traits & NSFontCondensedTrait ? Qcondensed :
199 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
200 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
201 make_number (100 + 100
202 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
204 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
205 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
206 ASET (font_entity, FONT_SPACING_INDEX,
207 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
208 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
210 ASET (font_entity, FONT_EXTRA_INDEX, extra);
211 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
215 fprintf (stderr, "created font_entity:\n ");
216 debug_print (font_entity);
219 free (escapedFamily);
224 /* Default font entity. */
226 ns_fallback_entity ()
228 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
229 fontDescriptor], Qnil, NULL);
233 /* Utility: get width of a char c in screen font sfont */
235 ns_char_width (NSFont *sfont, int c)
238 NSString *cstr = [NSString stringWithFormat: @"%c", c];
240 NSGlyph glyph = [sfont glyphWithName: cstr];
243 float w = [sfont advancementForGlyph: glyph].width;
249 NSDictionary *attrsDictionary =
250 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
251 w = [cstr sizeWithAttributes: attrsDictionary].width;
257 /* Return whether set1 covers set2 to a reasonable extent given by pct.
258 We check, out of each 16 unicode char range containing chars in set2,
259 whether at least one character is present in set1.
260 This must be true for pct of the pairs to consider it covering. */
262 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
264 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
265 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
266 int i, off = 0, tot = 0;
268 for (i=0; i<4096; i++, bytes1++, bytes2++)
272 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
275 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
276 return (float)off / tot < 1.0 - pct;
280 /* Convert :lang property to a script. Use of :lang property by font backend
281 seems to be limited for now (2009/05) to ja, zh, and ko. */
283 *ns_lang_to_script (Lisp_Object lang)
285 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
287 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
288 have more characters. */
289 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
291 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
298 /* Convert OTF 4-letter script code to emacs script name. (Why can't
299 everyone just use some standard unicode names for these?) */
301 *ns_otf_to_script (Lisp_Object otf)
303 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
304 return CONSP (script)
305 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
310 /* Convert a font registry, such as */
312 *ns_registry_to_script (char *reg)
314 Lisp_Object script, r, rts = Vns_reg_to_script;
317 r = XCAR (XCAR (rts));
318 if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
320 script = XCDR (XCAR (rts));
321 return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
329 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
330 plus registry regular property, for something that can be mapped to a
331 unicode script. Empty string returned if no script spec found. */
333 *ns_get_req_script (Lisp_Object font_spec)
335 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
336 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
338 /* The extra-bundle properties have priority. */
339 for ( ; CONSP (extra); extra = XCDR (extra))
341 Lisp_Object tmp = XCAR (extra);
344 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
345 if (EQ (key, QCscript) && SYMBOLP (val))
346 return [NSString stringWithUTF8String:
347 SDATA (SYMBOL_NAME (val))];
348 if (EQ (key, QClang) && SYMBOLP (val))
349 return ns_lang_to_script (val);
350 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
351 return ns_otf_to_script (val);
355 /* If we get here, check the charset portion of the registry. */
358 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
359 (which causes box rendering if we don't treat it like iso8858-1)
360 but also for ascii (which causes unnecessary font substitution). */
362 if (EQ (reg, Qiso10646_1))
365 return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
372 /* This small function is static in fontset.c. If it can be made public for
373 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
375 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
377 if (EQ (XCAR (arg), val))
380 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
382 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
387 /* Use the unicode range information in Vchar_script_table to convert a script
388 name into an NSCharacterSet. */
389 static NSCharacterSet
390 *ns_script_to_charset (NSString *scriptName)
392 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
393 Lisp_Object script = intern ([scriptName UTF8String]);
394 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
396 if (! NILP (Fmemq (script, script_list)))
398 Lisp_Object ranges, range_list;
400 ranges = Fcons (script, Qnil);
401 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
403 range_list = Fnreverse (XCDR (ranges));
404 if (! NILP (range_list))
406 for (; CONSP (range_list); range_list = XCDR (range_list))
408 int start = XINT (XCAR (XCAR (range_list)));
409 int end = XINT (XCDR (XCAR (range_list)));
411 debug_print (XCAR (range_list));
413 [charset addCharactersInRange:
414 NSMakeRange (start, end-start)];
422 /* Return an array of font families containing characters for the given
423 script, for the given coverage criterion, including at least LastResort.
424 Results are cached by script for faster access.
425 If none are found, we reduce the percentage and try again, until 5%.
426 This provides a font with at least some characters if such can be found.
427 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
428 (b) need approximate match as fonts covering full unicode ranges are rare. */
430 *ns_get_covering_families (NSString *script, float pct)
432 static NSMutableDictionary *scriptToFamilies = nil;
433 NSMutableSet *families;
436 NSLog(@"Request covering families for script: '%@'", script);
438 if (scriptToFamilies == nil)
439 scriptToFamilies = [[NSMutableDictionary alloc] init];
441 if ((families = [scriptToFamilies objectForKey: script]) == nil)
443 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
444 NSArray *allFamilies = [fontMgr availableFontFamilies];
446 if ([script length] == 0)
447 families = [NSMutableSet setWithArray: allFamilies];
450 NSCharacterSet *charset = ns_script_to_charset (script);
452 families = [NSMutableSet setWithCapacity: 10];
455 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
456 while (family = [allFamiliesEnum nextObject])
458 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
459 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
460 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
462 fset = [NSCharacterSet characterSetWithRange:
463 NSMakeRange (0, 127)];
464 if (ns_charset_covers(fset, charset, pct))
465 [families addObject: family];
468 if ([families count] > 0 || pct < 0.05)
473 if ([families count] == 0)
474 [families addObject: @"LastResort"];
476 [scriptToFamilies setObject: families forKey: script];
480 NSLog(@" returning %d families", [families count]);
485 /* Implementation for list() and match(). List() can return nil, match()
486 must return something. Strategy is to drop family name from attribute
487 matching set for match. */
489 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
491 Lisp_Object tem, list = Qnil;
492 NSFontDescriptor *fdesc, *desc;
494 NSArray *matchingDescs;
502 fprintf (stderr, "nsfont: %s for fontspec:\n ",
503 (isMatch ? "match" : "list"));
504 debug_print (font_spec);
507 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
509 fdesc = ns_spec_to_descriptor (font_spec);
510 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
512 [fkeys removeObject: NSFontFamilyAttribute];
514 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
516 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
517 [matchingDescs count]);
519 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
521 if (![cFamilies containsObject:
522 [desc objectForKey: NSFontFamilyAttribute]])
524 tem = ns_descriptor_to_entity (desc,
525 AREF (font_spec, FONT_EXTRA_INDEX),
529 list = Fcons (tem, list);
530 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
534 /* Add synthItal member if needed. */
535 family = [fdesc objectForKey: NSFontFamilyAttribute];
536 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
538 NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
539 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
540 fontDescriptorWithFamily: family];
541 list = Fcons (ns_descriptor_to_entity (sDesc,
542 AREF (font_spec, FONT_EXTRA_INDEX),
546 /* Return something if was a match and nothing found. */
548 return ns_fallback_entity ();
551 fprintf (stderr, " Returning %ld entities.\n",
552 (long) XINT (Flength (list)));
559 /* ==========================================================================
561 Font driver implementation
563 ========================================================================== */
566 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
567 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
568 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
569 static Lisp_Object nsfont_list_family (Lisp_Object frame);
570 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
572 static void nsfont_close (FRAME_PTR f, struct font *font);
573 static int nsfont_has_char (Lisp_Object entity, int c);
574 static unsigned int nsfont_encode_char (struct font *font, int c);
575 static int nsfont_text_extents (struct font *font, unsigned int *code,
576 int nglyphs, struct font_metrics *metrics);
577 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
578 int with_background);
580 struct font_driver nsfont_driver =
583 1, /* case sensitive */
588 NULL, /*free_entity */
591 NULL, /* prepare_face */
592 NULL, /* done_face */
597 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
598 anchor_point, otf_capability, otf_driver,
599 start_for_frame, end_for_frame, shape */
603 /* Return a cache of font-entities on FRAME. The cache must be a
604 cons whose cdr part is the actual cache area. */
606 nsfont_get_cache (FRAME_PTR frame)
608 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
609 return (dpyinfo->name_list_element);
613 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
614 **list** of font-entities. This and match () are sole APIs that allocate
615 font-entities. Properties to be considered (2009/05/19) are:
616 regular: foundry, family, adstyle, registry
617 extended: script, lang, otf
618 "Extended" properties are not part of the vector but get stored as
619 lisp properties under FONT_EXTRA_INDEX.
621 The returned entities should have type set (to 'ns), plus the following:
622 foundry, family, adstyle, registry,
623 weight, slant, width, size (0 if scalable),
624 dpi, spacing, avgwidth (0 if scalable) */
626 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
628 return ns_findfonts (font_spec, NO);
632 /* Return a font entity most closely maching with FONT_SPEC on
633 FRAME. The closeness is determined by the font backend, thus
634 `face-font-selection-order' is ignored here.
635 Properties to be considered are same as for list(). */
637 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
639 return ns_findfonts(font_spec, YES);
643 /* List available families. The value is a list of family names
646 nsfont_list_family (Lisp_Object frame)
648 Lisp_Object list = Qnil;
649 NSEnumerator *families =
650 [[[NSFontManager sharedFontManager] availableFontFamilies]
653 while (family = [families nextObject])
654 list = Fcons (intern ([family UTF8String]), list);
655 /* FIXME: escape the name? */
658 fprintf (stderr, "nsfont: list families returning %ld entries\n",
659 (long) XINT (Flength (list)));
665 /* Open a font specified by FONT_ENTITY on frame F. If the font is
666 scalable, open it with PIXEL_SIZE. */
668 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
671 unsigned int traits = 0;
672 struct nsfont_info *font_info;
674 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
675 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
677 NSFont *nsfont, *sfont;
680 Lisp_Object font_object;
683 static NSMutableDictionary *fontCache = nil;
686 /* 2008/03/08: The same font may end up being requested for different
687 entities, due to small differences in numeric values or other issues,
688 or for different copies of the same entity. Therefore we cache to
689 avoid creating multiple struct font objects (with metrics cache, etc.)
690 for the same NSFont object. */
691 if (fontCache == nil)
692 fontCache = [[NSMutableDictionary alloc] init];
696 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
697 debug_print (font_entity);
702 /* try to get it out of frame params */
703 Lisp_Object tem = get_frame_param (f, Qfontsize);
704 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
707 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
708 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
710 family = ns_get_family (font_entity);
712 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
713 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
714 when setting family in ns_spec_to_descriptor(). */
715 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
716 traits |= NSBoldFontMask;
717 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
718 traits |= NSItalicFontMask;
720 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
721 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
722 nsfont = [fontMgr fontWithFamily: family
723 traits: traits weight: fixLeopardBug
725 /* if didn't find, try synthetic italic */
726 if (nsfont == nil && synthItal)
728 nsfont = [fontMgr fontWithFamily: family
729 traits: traits & ~NSItalicFontMask
730 weight: fixLeopardBug size: pixel_size];
733 /* LastResort not really a family */
734 if (nsfont == nil && [@"LastResort" isEqualToString: family])
735 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
740 message_with_string ("*** Warning: font in family '%s' not found",
741 build_string ([family UTF8String]), 1);
742 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
746 NSLog (@"%@\n", nsfont);
748 /* Check the cache */
749 cached = [fontCache objectForKey: nsfont];
750 if (cached != nil && !synthItal)
753 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
754 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
755 XHASH (font_object) = [cached unsignedLongValue];
760 font_object = font_make_object (VECSIZE (struct nsfont_info),
761 font_entity, pixel_size);
763 [fontCache setObject: [NSNumber numberWithUnsignedLong:
764 (unsigned long) XHASH (font_object)]
768 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
769 font = (struct font *) font_info;
771 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
773 font_info->glyphs = (unsigned short **)
774 xmalloc (0x100 * sizeof (unsigned short *));
775 font_info->metrics = (struct font_metrics **)
776 xmalloc (0x100 * sizeof (struct font_metrics *));
777 if (!font_info->glyphs || !font_info->metrics)
779 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
780 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
785 sfont = [nsfont screenFont];
789 /* non-metric backend font struct fields */
790 font = (struct font *) font_info;
791 font->pixel_size = [sfont pointSize];
792 font->driver = &nsfont_driver;
793 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
794 font->encoding_charset = -1;
795 font->repertory_charset = -1;
796 font->default_ascent = 0;
797 font->vertical_centering = 0;
798 font->baseline_offset = 0;
799 font->relative_compose = 0;
800 font->font_encoder = NULL;
802 font->props[FONT_FORMAT_INDEX] = Qns;
803 font->props[FONT_FILE_INDEX] = Qnil;
806 double expand, hshrink;
807 float full_height, min_height, hd;
808 const char *fontName = [[nsfont fontName] UTF8String];
809 int len = strlen (fontName);
811 #ifdef NS_IMPL_GNUSTEP
812 font_info->nsfont = sfont;
814 font_info->nsfont = nsfont;
816 [font_info->nsfont retain];
818 /* set up ns_font (defined in nsgui.h) */
819 font_info->name = (char *)xmalloc (strlen (fontName) + 1);
820 bcopy (fontName, font_info->name, strlen (fontName) + 1);
821 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
823 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
825 /* Metrics etc.; some fonts return an unusually large max advance, so we
826 only use it for fonts that have wide characters. */
827 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
828 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
830 brect = [sfont boundingRectForFont];
831 full_height = brect.size.height;
832 min_height = [sfont ascender] - [sfont descender];
833 hd = full_height - min_height;
835 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
839 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
840 font_info->underwidth = [sfont underlineThickness];
841 font_info->size = font->pixel_size;
842 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
845 font_info->max_bounds.ascent =
846 lrint (hshrink * [sfont ascender] + expand * hd/2);
847 /* [sfont descender] is usually negative. Use floor to avoid
848 clipping descenders. */
849 font_info->max_bounds.descent =
850 -lrint (floor(hshrink* [sfont descender] - expand*hd/2));
852 font_info->max_bounds.ascent + font_info->max_bounds.descent;
853 font_info->max_bounds.width = lrint (font_info->width);
854 font_info->max_bounds.lbearing = lrint (brect.origin.x);
855 font_info->max_bounds.rbearing =
856 lrint (brect.size.width - font_info->width);
859 /* set up synthItal and the CG font */
860 font_info->synthItal = synthItal;
862 ATSFontRef atsFont = ATSFontFindFromPostScriptName
863 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
865 if (atsFont == kATSFontRefUnspecified)
867 /* see if we can get it by dropping italic (then synthesizing) */
868 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
869 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
870 fontName], kATSOptionFlagsDefault);
871 if (atsFont != kATSFontRefUnspecified)
872 font_info->synthItal = YES;
875 /* last resort fallback */
876 atsFont = ATSFontFindFromPostScriptName
877 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
880 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
884 /* set up metrics portion of font struct */
885 font->ascent = lrint([sfont ascender]);
886 font->descent = -lrint(floor([sfont descender]));
887 font->min_width = ns_char_width(sfont, '|');
888 font->space_width = lrint (ns_char_width (sfont, ' '));
889 font->average_width = lrint (font_info->width);
890 font->max_width = lrint (font_info->max_bounds.width);
891 font->height = lrint (font_info->height);
892 font->underline_position = lrint (font_info->underpos);
893 font->underline_thickness = lrint (font_info->underwidth);
895 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
896 font->props[FONT_FULLNAME_INDEX] =
897 make_unibyte_string (font_info->name, strlen (font_info->name));
905 /* Close FONT on frame F. */
907 nsfont_close (FRAME_PTR f, struct font *font)
909 struct nsfont_info *font_info = (struct nsfont_info *)font;
912 /* FIXME: this occurs apparently due to same failure to detect same font
913 that causes need for cache in nsfont_open () */
917 for (i =0; i<0x100; i++)
919 xfree (font_info->glyphs[i]);
920 xfree (font_info->metrics[i]);
922 [font_info->nsfont release];
924 CGFontRelease (font_info->cgfont);
926 xfree (font_info->name);
931 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
932 return 1. If not, return 0. If a font must be opened to check
935 nsfont_has_char (Lisp_Object entity, int c)
941 /* Return a glyph code of FONT for character C (Unicode code point).
942 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
944 nsfont_encode_char (struct font *font, int c)
946 struct nsfont_info *font_info = (struct nsfont_info *)font;
947 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
951 return FONT_INVALID_CODE;
953 /* did we already cache this block? */
954 if (!font_info->glyphs[high])
955 ns_uni_to_glyphs (font_info, high);
957 g = font_info->glyphs[high][low];
958 return g == 0xFFFF ? FONT_INVALID_CODE : g;
962 /* Perform the size computation of glyphs of FONT and fill in members
963 of METRICS. The glyphs are specified by their glyph codes in
964 CODE (length NGLYPHS). */
966 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
967 struct font_metrics *metrics)
969 struct nsfont_info *font_info = (struct nsfont_info *)font;
970 struct font_metrics *pcm;
971 unsigned char high, low;
975 bzero (metrics, sizeof (struct font_metrics));
977 for (i =0; i<nglyphs; i++)
979 /* get metrics for this glyph, filling cache if need be */
980 /* TODO: get metrics for whole string from an NSLayoutManager
982 high = (code[i] & 0xFF00) >> 8;
983 low = code[i] & 0x00FF;
984 if (!font_info->metrics[high])
985 ns_glyph_metrics (font_info, high);
986 pcm = &(font_info->metrics[high][low]);
988 if (metrics->lbearing > totalWidth + pcm->lbearing)
989 metrics->lbearing = totalWidth + pcm->lbearing;
990 if (metrics->rbearing < totalWidth + pcm->rbearing)
991 metrics->rbearing = totalWidth + pcm->rbearing;
992 if (metrics->ascent < pcm->ascent)
993 metrics->ascent = pcm->ascent;
994 if (metrics->descent < pcm->descent)
995 metrics->descent = pcm->descent;
997 totalWidth += pcm->width;
1000 metrics->width = totalWidth;
1002 return totalWidth; /* not specified in doc, but xfont.c does it */
1006 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1007 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
1008 is nonzero, fill the background in advance. It is assured that
1009 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1011 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1012 int with_background)
1013 /* NOTE: focus and clip must be set
1014 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1016 static char cbuf[1024];
1018 #ifdef NS_IMPL_GNUSTEP
1019 static float advances[1024];
1020 float *adv = advances;
1022 static CGSize advances[1024];
1023 CGSize *adv = advances;
1027 struct nsfont_info *font = ns_tmp_font;
1028 NSColor *col, *bgCol;
1029 unsigned short *t = s->char2b;
1031 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1032 int end = isComposite ? s->cmp_to : s->nchars;
1034 /* Select face based on input flags */
1035 switch (ns_tmp_flags)
1037 case NS_DUMPGLYPH_CURSOR:
1040 case NS_DUMPGLYPH_MOUSEFACE:
1041 face = FACE_FROM_ID (s->f,
1042 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1044 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1051 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1052 r.origin.x += abs (s->face->box_line_width);
1055 r.size.height = FONT_HEIGHT (font);
1057 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1058 NS to render the string, it will come out differently from the individual
1059 character widths added up because of layout processing. */
1062 int cwidth, twidth = 0;
1064 /* FIXME: composition: no vertical displacement is considered. */
1065 t += s->cmp_from; /* advance into composition */
1066 for (i = s->cmp_from; i < end; i++, t++)
1068 hi = (*t & 0xFF00) >> 8;
1072 if (!s->first_glyph->u.cmp.automatic)
1073 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1076 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1077 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1078 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1079 cwidth = LGLYPH_WIDTH (glyph);
1082 cwidth = LGLYPH_WADJUST (glyph);
1083 #ifdef NS_IMPL_GNUSTEP
1084 *(adv-1) += LGLYPH_XOFF (glyph);
1086 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1093 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1094 ns_glyph_metrics (font, hi);
1095 cwidth = font->metrics[hi][lo].width;
1098 #ifdef NS_IMPL_GNUSTEP
1100 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1102 (*adv++).width = cwidth;
1105 len = adv - advances;
1106 r.size.width = twidth;
1110 /* fill background if requested */
1111 if (with_background && !isComposite)
1114 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1115 int mbox_line_width = max (s->face->box_line_width, 0);
1117 if (s->row->full_width_p)
1119 if (br.origin.x <= fibw + 1 + mbox_line_width)
1121 br.size.width += br.origin.x - mbox_line_width;
1122 br.origin.x = mbox_line_width;
1124 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1126 br.size.width += fibw;
1128 if (s->face->box == FACE_NO_BOX)
1130 /* expand unboxed top row over internal border */
1131 if (br.origin.y <= fibw + 1 + mbox_line_width)
1133 br.size.height += br.origin.y;
1139 int correction = abs (s->face->box_line_width)+1;
1140 br.origin.y += correction;
1141 br.size.height -= 2*correction;
1142 br.origin.x += correction;
1143 br.size.width -= 2*correction;
1146 if (!s->face->stipple)
1147 [(NS_FACE_BACKGROUND (face) != 0
1148 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1149 : FRAME_BACKGROUND_COLOR (s->f)) set];
1152 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1153 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1159 /* set up for character rendering */
1160 r.origin.y += font->voffset + (s->height - font->height)/2;
1162 col = (NS_FACE_FOREGROUND (face) != 0
1163 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1164 : FRAME_FOREGROUND_COLOR (s->f));
1165 /* FIXME: find another way to pass this */
1166 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1167 : (NS_FACE_BACKGROUND (face) != 0
1168 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1169 : FRAME_BACKGROUND_COLOR (s->f)));
1171 /* render under GNUstep using DPS */
1172 #ifdef NS_IMPL_GNUSTEP
1174 NSGraphicsContext *context = GSCurrentContext ();
1179 /* do erase if "foreground" mode */
1183 DPSmoveto (context, r.origin.x, r.origin.y);
1184 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1185 DPSxshow (context, cbuf, advances, len);
1186 DPSstroke (context);
1188 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1192 if (face->underline_p)
1194 if (face->underline_color != 0)
1195 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1198 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1199 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1200 if (face->underline_color != 0)
1206 /* draw with DPSxshow () */
1207 DPSmoveto (context, r.origin.x, r.origin.y);
1208 DPSxshow (context, cbuf, advances, len);
1209 DPSstroke (context);
1211 DPSgrestore (context);
1215 #else /* NS_IMPL_COCOA */
1217 CGContextRef gcontext =
1218 [[NSGraphicsContext currentContext] graphicsPort];
1219 static CGAffineTransform fliptf;
1220 static BOOL firstTime = YES;
1225 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1228 CGContextSaveGState (gcontext);
1230 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1232 CGContextSetFont (gcontext, font->cgfont);
1233 CGContextSetFontSize (gcontext, font->size);
1234 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1235 CGContextSetShouldAntialias (gcontext, 0);
1237 CGContextSetShouldAntialias (gcontext, 1);
1239 CGContextSetTextMatrix (gcontext, fliptf);
1243 /* foreground drawing; erase first to avoid overstrike */
1245 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1246 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1247 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1248 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1251 if (face->underline_p)
1253 if (face->underline_color != 0)
1254 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1257 CGContextBeginPath (gcontext);
1258 CGContextMoveToPoint (gcontext,
1259 r.origin.x, r.origin.y + font->underpos);
1260 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1261 r.origin.y + font->underpos);
1262 CGContextStrokePath (gcontext);
1263 if (face->underline_color != 0)
1269 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1270 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1273 if (face->overstrike)
1275 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1276 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1280 CGContextRestoreGState (gcontext);
1283 #endif /* NS_IMPL_COCOA */
1289 /* ==========================================================================
1291 Font glyph and metrics caching functions
1293 ========================================================================== */
1295 /* Find and cache corresponding glyph codes for unicode values in given
1296 hi-byte block of 256. */
1298 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1300 #ifdef NS_IMPL_COCOA
1301 static EmacsGlyphStorage *glyphStorage;
1302 static char firstTime = 1;
1304 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1305 unsigned int i, g, idx;
1306 unsigned short *glyphs;
1309 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1314 #ifdef NS_IMPL_COCOA
1318 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1322 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1323 if (!unichars || !(font_info->glyphs[block]))
1326 /* create a string containing all unicode characters in this block */
1327 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1328 if (idx < 0xD800 || idx > 0xDFFF)
1331 unichars[i] = 0xFEFF;
1332 unichars[0x100] = 0;
1335 #ifdef NS_IMPL_COCOA
1336 NSString *allChars = [[NSString alloc]
1337 initWithCharactersNoCopy: unichars
1340 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1341 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1342 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1343 NSUInteger gInd =0, cInd =0;
1345 [glyphStorage setString: allChars font: font_info->nsfont];
1346 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1347 desiredNumberOfCharacters: glyphStorage->maxChar
1348 glyphIndex: &gInd characterIndex: &cInd];
1350 glyphs = font_info->glyphs[block];
1351 for (i =0; i<0x100; i++, glyphs++)
1353 #ifdef NS_IMPL_GNUSTEP
1356 g = glyphStorage->cglyphs[i];
1357 /* TODO: is this a good check? maybe need to use coveredChars.. */
1359 g = 0xFFFF; /* hopefully unused... */
1364 #ifdef NS_IMPL_COCOA
1374 /* Determine and cache metrics for corresponding glyph codes in given
1375 hi-byte block of 256. */
1377 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1380 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1382 struct font_metrics *metrics;
1385 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1388 #ifdef NS_IMPL_GNUSTEP
1389 /* not implemented yet (as of startup 0.18), so punt */
1391 numGlyphs = 0x10000;
1395 sfont = [font_info->nsfont screenFont];
1397 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1398 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1399 if (!(font_info->metrics[block]))
1402 metrics = font_info->metrics[block];
1403 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1406 NSRect r = [sfont boundingRectForGlyph: g];
1408 w = max ([sfont advancementForGlyph: g].width, 2.0);
1409 metrics->width = lrint (w);
1412 rb = r.size.width - w;
1414 metrics->lbearing = round (lb);
1415 if (font_info->ital)
1416 rb += 0.22 * font_info->height;
1417 metrics->rbearing = lrint (w + rb);
1419 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1420 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1421 metrics->ascent = r.size.height - metrics->descent;
1422 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1428 #ifdef NS_IMPL_COCOA
1429 /* helper for font glyph setup */
1430 @implementation EmacsGlyphStorage
1434 return [self initWithCapacity: 1024];
1437 - initWithCapacity: (unsigned long) c
1439 self = [super init];
1442 dict = [NSMutableDictionary new];
1443 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1456 - (void) setString: (NSString *)str font: (NSFont *)font
1458 [dict setObject: font forKey: NSFontAttributeName];
1459 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1460 maxChar = [str length];
1464 /* NSGlyphStorage protocol */
1465 - (NSUInteger)layoutOptions
1470 - (NSAttributedString *)attributedString
1475 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1476 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1477 characterIndex: (NSUInteger)charIndex
1479 len = glyphIndex+length;
1480 for (i =glyphIndex; i<len; i++)
1481 cglyphs[i] = glyphs[i-glyphIndex];
1486 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1487 forGlyphAtIndex: (NSUInteger)glyphIndex
1493 #endif /* NS_IMPL_COCOA */
1498 ns_dump_glyphstring (struct glyph_string *s)
1502 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1503 "overlap = %d, bg_filled = %d:",
1504 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1505 s->row->overlapping_p, s->background_filled_p);
1506 for (i =0; i<s->nchars; i++)
1507 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1508 fprintf (stderr, "\n");
1515 nsfont_driver.type = Qns;
1516 register_font_driver (&nsfont_driver, NULL);
1517 DEFSYM (Qapple, "apple");
1518 DEFSYM (Qroman, "roman");
1519 DEFSYM (Qmedium, "medium");
1520 DEFVAR_LISP ("ns-reg-to-script", &Vns_reg_to_script,
1521 doc: /* Internal use: maps font registry to unicode script. */);
1524 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae