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 family = [NSString stringWithUTF8String: tmp];
112 /* Return 0 if attr not set, else value (which might also be 0).
113 On Leopard 0 gets returned even on descriptors where the attribute
114 was never set, so there's no way to distinguish between unspecified
115 and set to not have. Callers should assume 0 means unspecified. */
117 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
119 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
120 NSNumber *val = [tdict objectForKey: trait];
121 return val == nil ? 0.0 : [val floatValue];
125 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
126 to NSFont descriptor. Information under extra only needed for matching. */
127 #define STYLE_REF 100
128 static NSFontDescriptor
129 *ns_spec_to_descriptor(Lisp_Object font_spec)
131 NSFontDescriptor *fdesc;
132 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
133 NSMutableDictionary *tdict = [NSMutableDictionary new];
134 NSString *family = ns_get_family (font_spec);
137 /* add each attr in font_spec to fdAttrs.. */
138 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
139 if (n != -1 && n != STYLE_REF)
140 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
141 forKey: NSFontWeightTrait];
142 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
143 if (n != -1 && n != STYLE_REF)
144 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
145 forKey: NSFontSlantTrait];
146 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
147 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
148 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
149 forKey: NSFontWidthTrait];
150 if ([tdict count] > 0)
151 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
153 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
155 fdesc = [fdesc fontDescriptorWithFamily: family];
160 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
162 ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
164 Lisp_Object font_entity = font_make_entity ();
165 /* NSString *psName = [desc postscriptName]; */
166 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
167 unsigned int traits = [desc symbolicTraits];
170 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
172 family = [desc objectForKey: NSFontNameAttribute];
174 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
176 escapedFamily = strdup ([family UTF8String]);
177 ns_escape_name (escapedFamily);
179 ASET (font_entity, FONT_TYPE_INDEX, Qns);
180 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
181 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
182 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
183 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
185 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
186 traits & NSFontBoldTrait ? Qbold : Qmedium);
187 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
188 make_number (100 + 100
189 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
190 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
191 traits & NSFontItalicTrait ? Qitalic : Qnormal);
192 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
193 make_number (100 + 100
194 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
195 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
196 traits & NSFontCondensedTrait ? Qcondensed :
197 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
198 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
199 make_number (100 + 100
200 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
202 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
203 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
204 ASET (font_entity, FONT_SPACING_INDEX,
205 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
206 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
208 ASET (font_entity, FONT_EXTRA_INDEX, extra);
209 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
213 fprintf (stderr, "created font_entity:\n ");
214 debug_print (font_entity);
217 free (escapedFamily);
222 /* Default font entity. */
224 ns_fallback_entity ()
226 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
227 fontDescriptor], Qnil, NULL);
231 /* Utility: get width of a char c in screen font sfont */
233 ns_char_width (NSFont *sfont, int c)
236 NSString *cstr = [NSString stringWithFormat: @"%c", c];
238 NSGlyph glyph = [sfont glyphWithName: cstr];
241 float w = [sfont advancementForGlyph: glyph].width;
246 w = [sfont widthOfString: cstr];
251 /* Return whether set1 covers set2 to a reasonable extent given by pct.
252 We check, out of each 16 unicode char range containing chars in set2,
253 whether at least one character is present in set1.
254 This must be true for pct of the pairs to consider it covering. */
256 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
258 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
259 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
260 int i, off = 0, tot = 0;
262 for (i=0; i<4096; i++, bytes1++, bytes2++)
266 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
269 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
270 return (float)off / tot < 1.0 - pct;
274 /* Convert :lang property to a script. Use of :lang property by font backend
275 seems to be limited for now (2009/05) to ja, zh, and ko. */
277 *ns_lang_to_script (Lisp_Object lang)
279 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
281 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
282 have more characters. */
283 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
285 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
292 /* Convert OTF 4-letter script code to emacs script name. (Why can't
293 everyone just use some standard unicode names for these?) */
295 *ns_otf_to_script (Lisp_Object otf)
297 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
298 return CONSP (script)
299 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
304 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec
305 for something that can be mapped to a unicode script. Empty string returned
306 if no script spec found.
307 TODO: Eventually registry / encoding should be checked and mapped, but for
308 now the font backend will try script/lang/otf if registry fails, so it is
311 *ns_get_req_script (Lisp_Object font_spec)
313 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
315 for ( ; CONSP (extra); extra = XCDR (extra))
317 Lisp_Object tmp = XCAR (extra);
320 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
321 if (EQ (key, QCscript) && SYMBOLP (val))
322 return [NSString stringWithUTF8String:
323 SDATA (SYMBOL_NAME (val))];
324 if (EQ (key, QClang) && SYMBOLP (val))
325 return ns_lang_to_script (val);
326 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
327 return ns_otf_to_script (val);
334 /* This small function is static in fontset.c. If it can be made public for
335 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
337 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
339 if (EQ (XCAR (arg), val))
342 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
344 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
349 /* Use the unicode range information in Vchar_script_table to convert a script
350 name into an NSCharacterSet. */
351 static NSCharacterSet
352 *ns_script_to_charset (NSString *scriptName)
354 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
355 Lisp_Object script = intern ([scriptName UTF8String]);
356 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
358 if (! NILP (Fmemq (script, script_list)))
360 Lisp_Object ranges, range_list;
362 ranges = Fcons (script, Qnil);
363 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
365 range_list = Fnreverse (XCDR (ranges));
366 if (! NILP (range_list))
368 for (; CONSP (range_list); range_list = XCDR (range_list))
370 int start = XINT (XCAR (XCAR (range_list)));
371 int end = XINT (XCDR (XCAR (range_list)));
373 debug_print (XCAR (range_list));
375 [charset addCharactersInRange:
376 NSMakeRange (start, end-start)];
384 /* Return an array of font families containing characters for the given
385 script, for the given coverage criterion, including at least LastResort.
386 Results are cached by script for faster access.
387 If none are found, we reduce the percentage and try again, until 5%.
388 This provides a font with at least some characters if such can be found.
389 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
390 (b) need approximate match as fonts covering full unicode ranges are rare. */
392 *ns_get_covering_families (NSString *script, float pct)
394 static NSMutableDictionary *scriptToFamilies = nil;
395 NSMutableSet *families;
398 NSLog(@"Request covering families for script: '%@'", script);
400 if (scriptToFamilies == nil)
401 scriptToFamilies = [[NSMutableDictionary alloc] init];
403 if ((families = [scriptToFamilies objectForKey: script]) == nil)
405 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
406 NSArray *allFamilies = [fontMgr availableFontFamilies];
408 if ([script length] == 0)
409 families = [NSMutableSet setWithArray: allFamilies];
412 NSCharacterSet *charset = ns_script_to_charset (script);
414 families = [NSMutableSet setWithCapacity: 10];
417 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
418 while (family = [allFamiliesEnum nextObject])
420 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
421 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
422 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
424 fset = [NSCharacterSet characterSetWithRange:
425 NSMakeRange (0, 127)];
426 if (ns_charset_covers(fset, charset, pct))
427 [families addObject: family];
430 if ([families count] > 0 || pct < 0.05)
435 if ([families count] == 0)
436 [families addObject: @"LastResort"];
438 [scriptToFamilies setObject: families forKey: script];
442 NSLog(@" returning %d families", [families count]);
447 /* Implementation for list() and match(). List() can return nil, match()
448 must return something. Strategy is to drop family name from attribute
449 matching set for match. */
451 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
453 Lisp_Object tem, list = Qnil;
454 NSFontDescriptor *fdesc, *desc;
456 NSArray *matchingDescs;
464 fprintf (stderr, "nsfont: %s for fontspec:\n ",
465 (isMatch ? "match" : "list"));
466 debug_print (font_spec);
469 /* If has non-unicode registry, give up. */
470 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
471 if (! NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
472 return isMatch ? ns_fallback_entity () : Qnil;
474 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
476 fdesc = ns_spec_to_descriptor (font_spec);
477 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
479 [fkeys removeObject: NSFontFamilyAttribute];
481 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
483 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
484 [matchingDescs count]);
486 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
488 if (![cFamilies containsObject:
489 [desc objectForKey: NSFontFamilyAttribute]])
491 tem = ns_descriptor_to_entity (desc,
492 AREF (font_spec, FONT_EXTRA_INDEX),
496 list = Fcons (tem, list);
497 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
501 /* Add synthItal member if needed. */
502 family = [fdesc objectForKey: NSFontFamilyAttribute];
503 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
505 NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
506 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
507 fontDescriptorWithFamily: family];
508 list = Fcons (ns_descriptor_to_entity (sDesc,
509 AREF (font_spec, FONT_EXTRA_INDEX),
513 /* Return something if was a match and nothing found. */
515 return ns_fallback_entity ();
518 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
525 /* ==========================================================================
527 Font driver implementation
529 ========================================================================== */
532 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
533 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
534 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
535 static Lisp_Object nsfont_list_family (Lisp_Object frame);
536 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
538 static void nsfont_close (FRAME_PTR f, struct font *font);
539 static int nsfont_has_char (Lisp_Object entity, int c);
540 static unsigned int nsfont_encode_char (struct font *font, int c);
541 static int nsfont_text_extents (struct font *font, unsigned int *code,
542 int nglyphs, struct font_metrics *metrics);
543 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
544 int with_background);
546 struct font_driver nsfont_driver =
549 1, /* case sensitive */
554 NULL, /*free_entity */
557 NULL, /* prepare_face */
558 NULL, /* done_face */
563 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
564 anchor_point, otf_capability, otf_driver,
565 start_for_frame, end_for_frame, shape */
569 /* Return a cache of font-entities on FRAME. The cache must be a
570 cons whose cdr part is the actual cache area. */
572 nsfont_get_cache (FRAME_PTR frame)
574 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
575 return (dpyinfo->name_list_element);
579 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
580 **list** of font-entities. This and match () are sole APIs that allocate
581 font-entities. Properties to be considered (2009/05/19) are:
582 regular: foundry, family, adstyle, registry
583 extended: script, lang, otf
584 "Extended" properties are not part of the vector but get stored as
585 lisp properties under FONT_EXTRA_INDEX.
587 The returned entities should have type set (to 'ns), plus the following:
588 foundry, family, adstyle, registry,
589 weight, slant, width, size (0 if scalable),
590 dpi, spacing, avgwidth (0 if scalable) */
592 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
594 return ns_findfonts (font_spec, NO);
598 /* Return a font entity most closely maching with FONT_SPEC on
599 FRAME. The closeness is determined by the font backend, thus
600 `face-font-selection-order' is ignored here.
601 Properties to be considered are same as for list(). */
603 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
605 return ns_findfonts(font_spec, YES);
609 /* List available families. The value is a list of family names
612 nsfont_list_family (Lisp_Object frame)
614 Lisp_Object list = Qnil;
615 NSEnumerator *families =
616 [[[NSFontManager sharedFontManager] availableFontFamilies]
619 while (family = [families nextObject])
620 list = Fcons (intern ([family UTF8String]), list);
621 /* FIXME: escape the name? */
624 fprintf (stderr, "nsfont: list families returning %d entries\n",
625 XINT (Flength (list)));
631 /* Open a font specified by FONT_ENTITY on frame F. If the font is
632 scalable, open it with PIXEL_SIZE. */
634 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
637 unsigned int traits = 0;
638 struct nsfont_info *font_info;
640 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
641 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
643 NSFont *nsfont, *sfont;
646 Lisp_Object font_object;
649 static NSMutableDictionary *fontCache = nil;
652 /* 2008/03/08: The same font may end up being requested for different
653 entities, due to small differences in numeric values or other issues,
654 or for different copies of the same entity. Therefore we cache to
655 avoid creating multiple struct font objects (with metrics cache, etc.)
656 for the same NSFont object. */
657 if (fontCache == nil)
658 fontCache = [[NSMutableDictionary alloc] init];
662 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
663 debug_print (font_entity);
668 /* try to get it out of frame params */
669 Lisp_Object tem = get_frame_param (f, Qfontsize);
670 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
673 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
674 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
676 family = ns_get_family (font_entity);
678 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
679 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
680 when setting family in ns_spec_to_descriptor(). */
681 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
682 traits |= NSBoldFontMask;
683 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
684 traits |= NSItalicFontMask;
686 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
687 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
688 nsfont = [fontMgr fontWithFamily: family
689 traits: traits weight: fixLeopardBug
691 /* if didn't find, try synthetic italic */
692 if (nsfont == nil && synthItal)
694 nsfont = [fontMgr fontWithFamily: family
695 traits: traits & ~NSItalicFontMask
696 weight: fixLeopardBug size: pixel_size];
699 /* LastResort not really a family */
700 if (nsfont == nil && [@"LastResort" isEqualToString: family])
701 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
706 message_with_string ("*** Warning: font in family '%s' not found",
707 build_string ([family UTF8String]), 1);
708 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
712 NSLog (@"%@\n", nsfont);
714 /* Check the cache */
715 cached = [fontCache objectForKey: nsfont];
716 if (cached != nil && !synthItal)
719 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
720 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
721 XHASH (font_object) = [cached unsignedLongValue];
726 font_object = font_make_object (VECSIZE (struct nsfont_info),
727 font_entity, pixel_size);
729 [fontCache setObject: [NSNumber numberWithUnsignedLong:
730 (unsigned long) XHASH (font_object)]
734 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
735 font = (struct font *) font_info;
737 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
739 font_info->glyphs = (unsigned short **)
740 xmalloc (0x100 * sizeof (unsigned short *));
741 font_info->metrics = (struct font_metrics **)
742 xmalloc (0x100 * sizeof (struct font_metrics *));
743 if (!font_info->glyphs || !font_info->metrics)
745 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
746 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
751 sfont = [nsfont screenFont];
755 /* non-metric backend font struct fields */
756 font = (struct font *) font_info;
757 font->pixel_size = [sfont pointSize];
758 font->driver = &nsfont_driver;
759 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
760 font->encoding_charset = -1;
761 font->repertory_charset = -1;
762 font->default_ascent = 0;
763 font->vertical_centering = 0;
764 font->baseline_offset = 0;
765 font->relative_compose = 0;
766 font->font_encoder = NULL;
768 font->props[FONT_FORMAT_INDEX] = Qns;
769 font->props[FONT_FILE_INDEX] = Qnil;
772 double expand, hshrink;
773 float full_height, min_height, hd;
774 const char *fontName = [[nsfont fontName] UTF8String];
775 int len = strlen (fontName);
777 #ifdef NS_IMPL_GNUSTEP
778 font_info->nsfont = sfont;
780 font_info->nsfont = nsfont;
782 [font_info->nsfont retain];
784 /* set up ns_font (defined in nsgui.h) */
785 font_info->name = (char *)xmalloc (strlen (fontName) + 1);
786 bcopy (fontName, font_info->name, strlen (fontName) + 1);
787 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
789 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
791 /* Metrics etc.; some fonts return an unusually large max advance, so we
792 only use it for fonts that have wide characters. */
793 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
794 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
796 brect = [sfont boundingRectForFont];
797 full_height = brect.size.height;
798 min_height = [sfont ascender] - [sfont descender];
799 hd = full_height - min_height;
801 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
805 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
806 font_info->underwidth = [sfont underlineThickness];
807 font_info->size = font->pixel_size;
808 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
811 font_info->max_bounds.ascent =
812 lrint (hshrink * [sfont ascender] + expand * hd/2);
813 font_info->max_bounds.descent =
814 -lrint (hshrink* [sfont descender] - expand*hd/2);
816 font_info->max_bounds.ascent + font_info->max_bounds.descent;
817 font_info->max_bounds.width = lrint (font_info->width);
818 font_info->max_bounds.lbearing = lrint (brect.origin.x);
819 font_info->max_bounds.rbearing =
820 lrint (brect.size.width - font_info->width);
823 /* set up synthItal and the CG font */
824 font_info->synthItal = synthItal;
826 ATSFontRef atsFont = ATSFontFindFromPostScriptName
827 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
829 if (atsFont == kATSFontRefUnspecified)
831 /* see if we can get it by dropping italic (then synthesizing) */
832 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
833 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
834 fontName], kATSOptionFlagsDefault);
835 if (atsFont != kATSFontRefUnspecified)
836 font_info->synthItal = YES;
839 /* last resort fallback */
840 atsFont = ATSFontFindFromPostScriptName
841 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
844 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
848 /* set up metrics portion of font struct */
849 font->ascent = [sfont ascender];
850 font->descent = -[sfont descender];
851 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
852 font->space_width = lrint (ns_char_width (sfont, ' '));
853 font->average_width = lrint (font_info->width);
854 font->max_width = lrint (font_info->max_bounds.width);
855 font->height = lrint (font_info->height);
856 font->underline_position = lrint (font_info->underpos);
857 font->underline_thickness = lrint (font_info->underwidth);
859 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
860 font->props[FONT_FULLNAME_INDEX] =
861 make_unibyte_string (font_info->name, strlen (font_info->name));
869 /* Close FONT on frame F. */
871 nsfont_close (FRAME_PTR f, struct font *font)
873 struct nsfont_info *font_info = (struct nsfont_info *)font;
876 /* FIXME: this occurs apparently due to same failure to detect same font
877 that causes need for cache in nsfont_open () */
881 for (i =0; i<0x100; i++)
883 xfree (font_info->glyphs[i]);
884 xfree (font_info->metrics[i]);
886 [font_info->nsfont release];
888 CGFontRelease (font_info->cgfont);
890 xfree (font_info->name);
895 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
896 return 1. If not, return 0. If a font must be opened to check
899 nsfont_has_char (Lisp_Object entity, int c)
905 /* Return a glyph code of FONT for character C (Unicode code point).
906 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
908 nsfont_encode_char (struct font *font, int c)
910 struct nsfont_info *font_info = (struct nsfont_info *)font;
911 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
915 return FONT_INVALID_CODE;
917 /* did we already cache this block? */
918 if (!font_info->glyphs[high])
919 ns_uni_to_glyphs (font_info, high);
921 g = font_info->glyphs[high][low];
922 return g == 0xFFFF ? FONT_INVALID_CODE : g;
926 /* Perform the size computation of glyphs of FONT and fill in members
927 of METRICS. The glyphs are specified by their glyph codes in
928 CODE (length NGLYPHS). */
930 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
931 struct font_metrics *metrics)
933 struct nsfont_info *font_info = (struct nsfont_info *)font;
934 struct font_metrics *pcm;
935 unsigned char high, low;
939 bzero (metrics, sizeof (struct font_metrics));
941 for (i =0; i<nglyphs; i++)
943 /* get metrics for this glyph, filling cache if need be */
944 /* TODO: get metrics for whole string from an NSLayoutManager
946 high = (code[i] & 0xFF00) >> 8;
947 low = code[i] & 0x00FF;
948 if (!font_info->metrics[high])
949 ns_glyph_metrics (font_info, high);
950 pcm = &(font_info->metrics[high][low]);
952 if (metrics->lbearing > totalWidth + pcm->lbearing)
953 metrics->lbearing = totalWidth + pcm->lbearing;
954 if (metrics->rbearing < totalWidth + pcm->rbearing)
955 metrics->rbearing = totalWidth + pcm->rbearing;
956 if (metrics->ascent < pcm->ascent)
957 metrics->ascent = pcm->ascent;
958 if (metrics->descent < pcm->descent)
959 metrics->descent = pcm->descent;
961 totalWidth += pcm->width;
964 metrics->width = totalWidth;
966 return totalWidth; /* not specified in doc, but xfont.c does it */
970 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
971 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
972 is nonzero, fill the background in advance. It is assured that
973 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
975 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
977 /* NOTE: focus and clip must be set
978 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
980 static char cbuf[1024];
982 #ifdef NS_IMPL_GNUSTEP
983 static float advances[1024];
984 float *adv = advances;
986 static CGSize advances[1024];
987 CGSize *adv = advances;
991 struct nsfont_info *font = ns_tmp_font;
992 NSColor *col, *bgCol;
993 unsigned short *t = s->char2b;
995 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
996 int end = isComposite ? s->cmp_to : s->nchars;
998 /* Select face based on input flags */
999 switch (ns_tmp_flags)
1001 case NS_DUMPGLYPH_CURSOR:
1004 case NS_DUMPGLYPH_MOUSEFACE:
1005 face = FACE_FROM_ID (s->f,
1006 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1008 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1015 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1016 r.origin.x += abs (s->face->box_line_width);
1019 r.size.height = FONT_HEIGHT (font);
1021 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1022 NS to render the string, it will come out differently from the individual
1023 character widths added up because of layout processing. */
1026 int cwidth, twidth = 0;
1028 /* FIXME: composition: no vertical displacement is considered. */
1029 t += s->cmp_from; /* advance into composition */
1030 for (i = s->cmp_from; i < end; i++, t++)
1032 hi = (*t & 0xFF00) >> 8;
1036 if (!s->first_glyph->u.cmp.automatic)
1037 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1040 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1041 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1042 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1043 cwidth = LGLYPH_WIDTH (glyph);
1046 cwidth = LGLYPH_WADJUST (glyph);
1047 #ifdef NS_IMPL_GNUSTEP
1048 *(adv-1) += LGLYPH_XOFF (glyph);
1050 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1057 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1058 ns_glyph_metrics (font, hi);
1059 cwidth = font->metrics[hi][lo].width;
1062 #ifdef NS_IMPL_GNUSTEP
1064 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1066 (*adv++).width = cwidth;
1069 len = adv - advances;
1070 r.size.width = twidth;
1074 /* fill background if requested */
1075 if (with_background && !isComposite)
1078 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1079 int mbox_line_width = max (s->face->box_line_width, 0);
1081 if (s->row->full_width_p)
1083 if (br.origin.x <= fibw + 1 + mbox_line_width)
1085 br.size.width += br.origin.x - mbox_line_width;
1086 br.origin.x = mbox_line_width;
1088 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1090 br.size.width += fibw;
1092 if (s->face->box == FACE_NO_BOX)
1094 /* expand unboxed top row over internal border */
1095 if (br.origin.y <= fibw + 1 + mbox_line_width)
1097 br.size.height += br.origin.y;
1103 int correction = abs (s->face->box_line_width)+1;
1104 br.origin.y += correction;
1105 br.size.height -= 2*correction;
1106 br.origin.x += correction;
1107 br.size.width -= 2*correction;
1110 if (!s->face->stipple)
1111 [(NS_FACE_BACKGROUND (face) != 0
1112 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1113 : FRAME_BACKGROUND_COLOR (s->f)) set];
1116 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1117 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1123 /* set up for character rendering */
1124 r.origin.y += font->voffset + (s->height - font->height)/2;
1126 col = (NS_FACE_FOREGROUND (face) != 0
1127 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1128 : FRAME_FOREGROUND_COLOR (s->f));
1129 /* FIXME: find another way to pass this */
1130 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1131 : (NS_FACE_BACKGROUND (face) != 0
1132 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1133 : FRAME_BACKGROUND_COLOR (s->f)));
1135 /* render under GNUstep using DPS */
1136 #ifdef NS_IMPL_GNUSTEP
1138 NSGraphicsContext *context = GSCurrentContext ();
1143 /* do erase if "foreground" mode */
1147 DPSmoveto (context, r.origin.x, r.origin.y);
1148 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1149 DPSxshow (context, cbuf, advances, len);
1150 DPSstroke (context);
1152 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1156 if (face->underline_p)
1158 if (face->underline_color != 0)
1159 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1162 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1163 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1164 if (face->underline_color != 0)
1170 /* draw with DPSxshow () */
1171 DPSmoveto (context, r.origin.x, r.origin.y);
1172 DPSxshow (context, cbuf, advances, len);
1173 DPSstroke (context);
1175 DPSgrestore (context);
1179 #else /* NS_IMPL_COCOA */
1181 CGContextRef gcontext =
1182 [[NSGraphicsContext currentContext] graphicsPort];
1183 static CGAffineTransform fliptf;
1184 static BOOL firstTime = YES;
1189 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1192 CGContextSaveGState (gcontext);
1194 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1196 CGContextSetFont (gcontext, font->cgfont);
1197 CGContextSetFontSize (gcontext, font->size);
1198 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1199 CGContextSetShouldAntialias (gcontext, 0);
1201 CGContextSetShouldAntialias (gcontext, 1);
1202 if (EQ (ns_use_qd_smoothing, Qt))
1203 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1205 CGContextSetTextMatrix (gcontext, fliptf);
1209 /* foreground drawing; erase first to avoid overstrike */
1211 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1212 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1213 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1214 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1217 if (face->underline_p)
1219 if (face->underline_color != 0)
1220 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1223 CGContextBeginPath (gcontext);
1224 CGContextMoveToPoint (gcontext,
1225 r.origin.x, r.origin.y + font->underpos);
1226 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1227 r.origin.y + font->underpos);
1228 CGContextStrokePath (gcontext);
1229 if (face->underline_color != 0)
1235 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1236 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1239 if (face->overstrike)
1241 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1242 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1246 CGContextRestoreGState (gcontext);
1249 #endif /* NS_IMPL_COCOA */
1255 /* ==========================================================================
1257 Font glyph and metrics caching functions
1259 ========================================================================== */
1261 /* Find and cache corresponding glyph codes for unicode values in given
1262 hi-byte block of 256. */
1264 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1266 #ifdef NS_IMPL_COCOA
1267 static EmacsGlyphStorage *glyphStorage;
1268 static char firstTime = 1;
1270 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1271 unsigned int i, g, idx;
1272 unsigned short *glyphs;
1275 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1280 #ifdef NS_IMPL_COCOA
1284 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1288 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1289 if (!unichars || !(font_info->glyphs[block]))
1292 /* create a string containing all unicode characters in this block */
1293 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1294 if (idx < 0xD800 || idx > 0xDFFF)
1297 unichars[i] = 0xFEFF;
1298 unichars[0x100] = 0;
1301 #ifdef NS_IMPL_COCOA
1302 NSString *allChars = [[NSString alloc]
1303 initWithCharactersNoCopy: unichars
1306 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1307 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1308 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1309 unsigned int gInd =0, cInd =0;
1311 [glyphStorage setString: allChars font: font_info->nsfont];
1312 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1313 desiredNumberOfCharacters: glyphStorage->maxChar
1314 glyphIndex: &gInd characterIndex: &cInd];
1316 glyphs = font_info->glyphs[block];
1317 for (i =0; i<0x100; i++, glyphs++)
1319 #ifdef NS_IMPL_GNUSTEP
1322 g = glyphStorage->cglyphs[i];
1323 /* TODO: is this a good check? maybe need to use coveredChars.. */
1325 g = 0xFFFF; /* hopefully unused... */
1330 #ifdef NS_IMPL_COCOA
1340 /* Determine and cache metrics for corresponding glyph codes in given
1341 hi-byte block of 256. */
1343 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1346 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1348 struct font_metrics *metrics;
1351 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1354 #ifdef NS_IMPL_GNUSTEP
1355 /* not implemented yet (as of startup 0.18), so punt */
1357 numGlyphs = 0x10000;
1361 sfont = [font_info->nsfont screenFont];
1363 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1364 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1365 if (!(font_info->metrics[block]))
1368 metrics = font_info->metrics[block];
1369 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1372 NSRect r = [sfont boundingRectForGlyph: g];
1374 #ifdef NS_IMPL_GNUSTEP
1377 NSString *s = [NSString stringWithFormat: @"%c", g];
1378 w = [sfont widthOfString: s];
1381 w = [sfont advancementForGlyph: g].width;
1384 metrics->width = lrint (w);
1387 rb = r.size.width - w;
1389 metrics->lbearing = round (lb);
1390 if (font_info->ital)
1391 rb += 0.22 * font_info->height;
1392 metrics->rbearing = lrint (w + rb);
1394 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1395 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1396 metrics->ascent = r.size.height - metrics->descent;
1397 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1403 #ifdef NS_IMPL_COCOA
1404 /* helper for font glyph setup */
1405 @implementation EmacsGlyphStorage
1409 return [self initWithCapacity: 1024];
1412 - initWithCapacity: (unsigned long) c
1414 self = [super init];
1417 dict = [NSMutableDictionary new];
1418 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1431 - (void) setString: (NSString *)str font: (NSFont *)font
1433 [dict setObject: font forKey: NSFontAttributeName];
1434 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1435 maxChar = [str length];
1439 /* NSGlyphStorage protocol */
1440 - (unsigned int)layoutOptions
1445 - (NSAttributedString *)attributedString
1450 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1451 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1452 characterIndex: (unsigned int)charIndex
1454 len = glyphIndex+length;
1455 for (i =glyphIndex; i<len; i++)
1456 cglyphs[i] = glyphs[i-glyphIndex];
1461 - (void)setIntAttribute: (int)attributeTag value: (int)val
1462 forGlyphAtIndex: (unsigned)glyphIndex
1468 #endif /* NS_IMPL_COCOA */
1473 ns_dump_glyphstring (struct glyph_string *s)
1477 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1478 "overlap = %d, bg_filled = %d:",
1479 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1480 s->row->overlapping_p, s->background_filled_p);
1481 for (i =0; i<s->nchars; i++)
1482 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1483 fprintf (stderr, "\n");
1490 nsfont_driver.type = Qns;
1491 register_font_driver (&nsfont_driver, NULL);
1492 DEFSYM (Qapple, "apple");
1493 DEFSYM (Qroman, "roman");
1494 DEFSYM (Qmedium, "medium");
1497 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae