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 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;
248 w = [sfont widthOfString: cstr];
253 /* Return whether set1 covers set2 to a reasonable extent given by pct.
254 We check, out of each 16 unicode char range containing chars in set2,
255 whether at least one character is present in set1.
256 This must be true for pct of the pairs to consider it covering. */
258 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
260 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
261 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
262 int i, off = 0, tot = 0;
264 for (i=0; i<4096; i++, bytes1++, bytes2++)
268 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
271 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
272 return (float)off / tot < 1.0 - pct;
276 /* Convert :lang property to a script. Use of :lang property by font backend
277 seems to be limited for now (2009/05) to ja, zh, and ko. */
279 *ns_lang_to_script (Lisp_Object lang)
281 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
283 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
284 have more characters. */
285 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
287 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
294 /* Convert OTF 4-letter script code to emacs script name. (Why can't
295 everyone just use some standard unicode names for these?) */
297 *ns_otf_to_script (Lisp_Object otf)
299 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
300 return CONSP (script)
301 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
306 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec
307 for something that can be mapped to a unicode script. Empty string returned
308 if no script spec found.
309 TODO: Eventually registry / encoding should be checked and mapped, but for
310 now the font backend will try script/lang/otf if registry fails, so it is
313 *ns_get_req_script (Lisp_Object font_spec)
315 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
317 for ( ; CONSP (extra); extra = XCDR (extra))
319 Lisp_Object tmp = XCAR (extra);
322 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
323 if (EQ (key, QCscript) && SYMBOLP (val))
324 return [NSString stringWithUTF8String:
325 SDATA (SYMBOL_NAME (val))];
326 if (EQ (key, QClang) && SYMBOLP (val))
327 return ns_lang_to_script (val);
328 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
329 return ns_otf_to_script (val);
336 /* This small function is static in fontset.c. If it can be made public for
337 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
339 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
341 if (EQ (XCAR (arg), val))
344 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
346 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
351 /* Use the unicode range information in Vchar_script_table to convert a script
352 name into an NSCharacterSet. */
353 static NSCharacterSet
354 *ns_script_to_charset (NSString *scriptName)
356 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
357 Lisp_Object script = intern ([scriptName UTF8String]);
358 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
360 if (! NILP (Fmemq (script, script_list)))
362 Lisp_Object ranges, range_list;
364 ranges = Fcons (script, Qnil);
365 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
367 range_list = Fnreverse (XCDR (ranges));
368 if (! NILP (range_list))
370 for (; CONSP (range_list); range_list = XCDR (range_list))
372 int start = XINT (XCAR (XCAR (range_list)));
373 int end = XINT (XCDR (XCAR (range_list)));
375 debug_print (XCAR (range_list));
377 [charset addCharactersInRange:
378 NSMakeRange (start, end-start)];
386 /* Return an array of font families containing characters for the given
387 script, for the given coverage criterion, including at least LastResort.
388 Results are cached by script for faster access.
389 If none are found, we reduce the percentage and try again, until 5%.
390 This provides a font with at least some characters if such can be found.
391 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
392 (b) need approximate match as fonts covering full unicode ranges are rare. */
394 *ns_get_covering_families (NSString *script, float pct)
396 static NSMutableDictionary *scriptToFamilies = nil;
397 NSMutableSet *families;
400 NSLog(@"Request covering families for script: '%@'", script);
402 if (scriptToFamilies == nil)
403 scriptToFamilies = [[NSMutableDictionary alloc] init];
405 if ((families = [scriptToFamilies objectForKey: script]) == nil)
407 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
408 NSArray *allFamilies = [fontMgr availableFontFamilies];
410 if ([script length] == 0)
411 families = [NSMutableSet setWithArray: allFamilies];
414 NSCharacterSet *charset = ns_script_to_charset (script);
416 families = [NSMutableSet setWithCapacity: 10];
419 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
420 while (family = [allFamiliesEnum nextObject])
422 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
423 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
424 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
426 fset = [NSCharacterSet characterSetWithRange:
427 NSMakeRange (0, 127)];
428 if (ns_charset_covers(fset, charset, pct))
429 [families addObject: family];
432 if ([families count] > 0 || pct < 0.05)
437 if ([families count] == 0)
438 [families addObject: @"LastResort"];
440 [scriptToFamilies setObject: families forKey: script];
444 NSLog(@" returning %d families", [families count]);
449 /* Implementation for list() and match(). List() can return nil, match()
450 must return something. Strategy is to drop family name from attribute
451 matching set for match. */
453 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
455 Lisp_Object tem, list = Qnil;
456 NSFontDescriptor *fdesc, *desc;
458 NSArray *matchingDescs;
466 fprintf (stderr, "nsfont: %s for fontspec:\n ",
467 (isMatch ? "match" : "list"));
468 debug_print (font_spec);
471 /* If has non-unicode registry, give up. */
472 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
473 if (! NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
474 return isMatch ? ns_fallback_entity () : Qnil;
476 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
478 fdesc = ns_spec_to_descriptor (font_spec);
479 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
481 [fkeys removeObject: NSFontFamilyAttribute];
483 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
485 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
486 [matchingDescs count]);
488 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
490 if (![cFamilies containsObject:
491 [desc objectForKey: NSFontFamilyAttribute]])
493 tem = ns_descriptor_to_entity (desc,
494 AREF (font_spec, FONT_EXTRA_INDEX),
498 list = Fcons (tem, list);
499 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
503 /* Add synthItal member if needed. */
504 family = [fdesc objectForKey: NSFontFamilyAttribute];
505 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
507 NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
508 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
509 fontDescriptorWithFamily: family];
510 list = Fcons (ns_descriptor_to_entity (sDesc,
511 AREF (font_spec, FONT_EXTRA_INDEX),
515 /* Return something if was a match and nothing found. */
517 return ns_fallback_entity ();
520 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
527 /* ==========================================================================
529 Font driver implementation
531 ========================================================================== */
534 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
535 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
536 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
537 static Lisp_Object nsfont_list_family (Lisp_Object frame);
538 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
540 static void nsfont_close (FRAME_PTR f, struct font *font);
541 static int nsfont_has_char (Lisp_Object entity, int c);
542 static unsigned int nsfont_encode_char (struct font *font, int c);
543 static int nsfont_text_extents (struct font *font, unsigned int *code,
544 int nglyphs, struct font_metrics *metrics);
545 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
546 int with_background);
548 struct font_driver nsfont_driver =
551 1, /* case sensitive */
556 NULL, /*free_entity */
559 NULL, /* prepare_face */
560 NULL, /* done_face */
565 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
566 anchor_point, otf_capability, otf_driver,
567 start_for_frame, end_for_frame, shape */
571 /* Return a cache of font-entities on FRAME. The cache must be a
572 cons whose cdr part is the actual cache area. */
574 nsfont_get_cache (FRAME_PTR frame)
576 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
577 return (dpyinfo->name_list_element);
581 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
582 **list** of font-entities. This and match () are sole APIs that allocate
583 font-entities. Properties to be considered (2009/05/19) are:
584 regular: foundry, family, adstyle, registry
585 extended: script, lang, otf
586 "Extended" properties are not part of the vector but get stored as
587 lisp properties under FONT_EXTRA_INDEX.
589 The returned entities should have type set (to 'ns), plus the following:
590 foundry, family, adstyle, registry,
591 weight, slant, width, size (0 if scalable),
592 dpi, spacing, avgwidth (0 if scalable) */
594 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
596 return ns_findfonts (font_spec, NO);
600 /* Return a font entity most closely maching with FONT_SPEC on
601 FRAME. The closeness is determined by the font backend, thus
602 `face-font-selection-order' is ignored here.
603 Properties to be considered are same as for list(). */
605 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
607 return ns_findfonts(font_spec, YES);
611 /* List available families. The value is a list of family names
614 nsfont_list_family (Lisp_Object frame)
616 Lisp_Object list = Qnil;
617 NSEnumerator *families =
618 [[[NSFontManager sharedFontManager] availableFontFamilies]
621 while (family = [families nextObject])
622 list = Fcons (intern ([family UTF8String]), list);
623 /* FIXME: escape the name? */
626 fprintf (stderr, "nsfont: list families returning %d entries\n",
627 XINT (Flength (list)));
633 /* Open a font specified by FONT_ENTITY on frame F. If the font is
634 scalable, open it with PIXEL_SIZE. */
636 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
639 unsigned int traits = 0;
640 struct nsfont_info *font_info;
642 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
643 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
645 NSFont *nsfont, *sfont;
648 Lisp_Object font_object;
651 static NSMutableDictionary *fontCache = nil;
654 /* 2008/03/08: The same font may end up being requested for different
655 entities, due to small differences in numeric values or other issues,
656 or for different copies of the same entity. Therefore we cache to
657 avoid creating multiple struct font objects (with metrics cache, etc.)
658 for the same NSFont object. */
659 if (fontCache == nil)
660 fontCache = [[NSMutableDictionary alloc] init];
664 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
665 debug_print (font_entity);
670 /* try to get it out of frame params */
671 Lisp_Object tem = get_frame_param (f, Qfontsize);
672 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
675 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
676 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
678 family = ns_get_family (font_entity);
680 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
681 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
682 when setting family in ns_spec_to_descriptor(). */
683 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
684 traits |= NSBoldFontMask;
685 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
686 traits |= NSItalicFontMask;
688 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
689 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
690 nsfont = [fontMgr fontWithFamily: family
691 traits: traits weight: fixLeopardBug
693 /* if didn't find, try synthetic italic */
694 if (nsfont == nil && synthItal)
696 nsfont = [fontMgr fontWithFamily: family
697 traits: traits & ~NSItalicFontMask
698 weight: fixLeopardBug size: pixel_size];
701 /* LastResort not really a family */
702 if (nsfont == nil && [@"LastResort" isEqualToString: family])
703 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
708 message_with_string ("*** Warning: font in family '%s' not found",
709 build_string ([family UTF8String]), 1);
710 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
714 NSLog (@"%@\n", nsfont);
716 /* Check the cache */
717 cached = [fontCache objectForKey: nsfont];
718 if (cached != nil && !synthItal)
721 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
722 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
723 XHASH (font_object) = [cached unsignedLongValue];
728 font_object = font_make_object (VECSIZE (struct nsfont_info),
729 font_entity, pixel_size);
731 [fontCache setObject: [NSNumber numberWithUnsignedLong:
732 (unsigned long) XHASH (font_object)]
736 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
737 font = (struct font *) font_info;
739 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
741 font_info->glyphs = (unsigned short **)
742 xmalloc (0x100 * sizeof (unsigned short *));
743 font_info->metrics = (struct font_metrics **)
744 xmalloc (0x100 * sizeof (struct font_metrics *));
745 if (!font_info->glyphs || !font_info->metrics)
747 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
748 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
753 sfont = [nsfont screenFont];
757 /* non-metric backend font struct fields */
758 font = (struct font *) font_info;
759 font->pixel_size = [sfont pointSize];
760 font->driver = &nsfont_driver;
761 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
762 font->encoding_charset = -1;
763 font->repertory_charset = -1;
764 font->default_ascent = 0;
765 font->vertical_centering = 0;
766 font->baseline_offset = 0;
767 font->relative_compose = 0;
768 font->font_encoder = NULL;
770 font->props[FONT_FORMAT_INDEX] = Qns;
771 font->props[FONT_FILE_INDEX] = Qnil;
774 double expand, hshrink;
775 float full_height, min_height, hd;
776 const char *fontName = [[nsfont fontName] UTF8String];
777 int len = strlen (fontName);
779 #ifdef NS_IMPL_GNUSTEP
780 font_info->nsfont = sfont;
782 font_info->nsfont = nsfont;
784 [font_info->nsfont retain];
786 /* set up ns_font (defined in nsgui.h) */
787 font_info->name = (char *)xmalloc (strlen (fontName) + 1);
788 bcopy (fontName, font_info->name, strlen (fontName) + 1);
789 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
791 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
793 /* Metrics etc.; some fonts return an unusually large max advance, so we
794 only use it for fonts that have wide characters. */
795 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
796 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
798 brect = [sfont boundingRectForFont];
799 full_height = brect.size.height;
800 min_height = [sfont ascender] - [sfont descender];
801 hd = full_height - min_height;
803 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
807 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
808 font_info->underwidth = [sfont underlineThickness];
809 font_info->size = font->pixel_size;
810 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
813 font_info->max_bounds.ascent =
814 lrint (hshrink * [sfont ascender] + expand * hd/2);
815 font_info->max_bounds.descent =
816 -lrint (hshrink* [sfont descender] - expand*hd/2);
818 font_info->max_bounds.ascent + font_info->max_bounds.descent;
819 font_info->max_bounds.width = lrint (font_info->width);
820 font_info->max_bounds.lbearing = lrint (brect.origin.x);
821 font_info->max_bounds.rbearing =
822 lrint (brect.size.width - font_info->width);
825 /* set up synthItal and the CG font */
826 font_info->synthItal = synthItal;
828 ATSFontRef atsFont = ATSFontFindFromPostScriptName
829 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
831 if (atsFont == kATSFontRefUnspecified)
833 /* see if we can get it by dropping italic (then synthesizing) */
834 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
835 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
836 fontName], kATSOptionFlagsDefault);
837 if (atsFont != kATSFontRefUnspecified)
838 font_info->synthItal = YES;
841 /* last resort fallback */
842 atsFont = ATSFontFindFromPostScriptName
843 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
846 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
850 /* set up metrics portion of font struct */
851 font->ascent = [sfont ascender];
852 font->descent = -[sfont descender];
853 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
854 font->space_width = lrint (ns_char_width (sfont, ' '));
855 font->average_width = lrint (font_info->width);
856 font->max_width = lrint (font_info->max_bounds.width);
857 font->height = lrint (font_info->height);
858 font->underline_position = lrint (font_info->underpos);
859 font->underline_thickness = lrint (font_info->underwidth);
861 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
862 font->props[FONT_FULLNAME_INDEX] =
863 make_unibyte_string (font_info->name, strlen (font_info->name));
871 /* Close FONT on frame F. */
873 nsfont_close (FRAME_PTR f, struct font *font)
875 struct nsfont_info *font_info = (struct nsfont_info *)font;
878 /* FIXME: this occurs apparently due to same failure to detect same font
879 that causes need for cache in nsfont_open () */
883 for (i =0; i<0x100; i++)
885 xfree (font_info->glyphs[i]);
886 xfree (font_info->metrics[i]);
888 [font_info->nsfont release];
890 CGFontRelease (font_info->cgfont);
892 xfree (font_info->name);
897 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
898 return 1. If not, return 0. If a font must be opened to check
901 nsfont_has_char (Lisp_Object entity, int c)
907 /* Return a glyph code of FONT for character C (Unicode code point).
908 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
910 nsfont_encode_char (struct font *font, int c)
912 struct nsfont_info *font_info = (struct nsfont_info *)font;
913 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
917 return FONT_INVALID_CODE;
919 /* did we already cache this block? */
920 if (!font_info->glyphs[high])
921 ns_uni_to_glyphs (font_info, high);
923 g = font_info->glyphs[high][low];
924 return g == 0xFFFF ? FONT_INVALID_CODE : g;
928 /* Perform the size computation of glyphs of FONT and fill in members
929 of METRICS. The glyphs are specified by their glyph codes in
930 CODE (length NGLYPHS). */
932 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
933 struct font_metrics *metrics)
935 struct nsfont_info *font_info = (struct nsfont_info *)font;
936 struct font_metrics *pcm;
937 unsigned char high, low;
941 bzero (metrics, sizeof (struct font_metrics));
943 for (i =0; i<nglyphs; i++)
945 /* get metrics for this glyph, filling cache if need be */
946 /* TODO: get metrics for whole string from an NSLayoutManager
948 high = (code[i] & 0xFF00) >> 8;
949 low = code[i] & 0x00FF;
950 if (!font_info->metrics[high])
951 ns_glyph_metrics (font_info, high);
952 pcm = &(font_info->metrics[high][low]);
954 if (metrics->lbearing > totalWidth + pcm->lbearing)
955 metrics->lbearing = totalWidth + pcm->lbearing;
956 if (metrics->rbearing < totalWidth + pcm->rbearing)
957 metrics->rbearing = totalWidth + pcm->rbearing;
958 if (metrics->ascent < pcm->ascent)
959 metrics->ascent = pcm->ascent;
960 if (metrics->descent < pcm->descent)
961 metrics->descent = pcm->descent;
963 totalWidth += pcm->width;
966 metrics->width = totalWidth;
968 return totalWidth; /* not specified in doc, but xfont.c does it */
972 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
973 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
974 is nonzero, fill the background in advance. It is assured that
975 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
977 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
979 /* NOTE: focus and clip must be set
980 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
982 static char cbuf[1024];
984 #ifdef NS_IMPL_GNUSTEP
985 static float advances[1024];
986 float *adv = advances;
988 static CGSize advances[1024];
989 CGSize *adv = advances;
993 struct nsfont_info *font = ns_tmp_font;
994 NSColor *col, *bgCol;
995 unsigned short *t = s->char2b;
997 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
998 int end = isComposite ? s->cmp_to : s->nchars;
1000 /* Select face based on input flags */
1001 switch (ns_tmp_flags)
1003 case NS_DUMPGLYPH_CURSOR:
1006 case NS_DUMPGLYPH_MOUSEFACE:
1007 face = FACE_FROM_ID (s->f,
1008 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1010 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1017 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1018 r.origin.x += abs (s->face->box_line_width);
1021 r.size.height = FONT_HEIGHT (font);
1023 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1024 NS to render the string, it will come out differently from the individual
1025 character widths added up because of layout processing. */
1028 int cwidth, twidth = 0;
1030 /* FIXME: composition: no vertical displacement is considered. */
1031 t += s->cmp_from; /* advance into composition */
1032 for (i = s->cmp_from; i < end; i++, t++)
1034 hi = (*t & 0xFF00) >> 8;
1038 if (!s->first_glyph->u.cmp.automatic)
1039 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1042 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1043 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1044 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1045 cwidth = LGLYPH_WIDTH (glyph);
1048 cwidth = LGLYPH_WADJUST (glyph);
1049 #ifdef NS_IMPL_GNUSTEP
1050 *(adv-1) += LGLYPH_XOFF (glyph);
1052 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1059 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1060 ns_glyph_metrics (font, hi);
1061 cwidth = font->metrics[hi][lo].width;
1064 #ifdef NS_IMPL_GNUSTEP
1066 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1068 (*adv++).width = cwidth;
1071 len = adv - advances;
1072 r.size.width = twidth;
1076 /* fill background if requested */
1077 if (with_background && !isComposite)
1080 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1081 int mbox_line_width = max (s->face->box_line_width, 0);
1083 if (s->row->full_width_p)
1085 if (br.origin.x <= fibw + 1 + mbox_line_width)
1087 br.size.width += br.origin.x - mbox_line_width;
1088 br.origin.x = mbox_line_width;
1090 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1092 br.size.width += fibw;
1094 if (s->face->box == FACE_NO_BOX)
1096 /* expand unboxed top row over internal border */
1097 if (br.origin.y <= fibw + 1 + mbox_line_width)
1099 br.size.height += br.origin.y;
1105 int correction = abs (s->face->box_line_width)+1;
1106 br.origin.y += correction;
1107 br.size.height -= 2*correction;
1108 br.origin.x += correction;
1109 br.size.width -= 2*correction;
1112 if (!s->face->stipple)
1113 [(NS_FACE_BACKGROUND (face) != 0
1114 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1115 : FRAME_BACKGROUND_COLOR (s->f)) set];
1118 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1119 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1125 /* set up for character rendering */
1126 r.origin.y += font->voffset + (s->height - font->height)/2;
1128 col = (NS_FACE_FOREGROUND (face) != 0
1129 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1130 : FRAME_FOREGROUND_COLOR (s->f));
1131 /* FIXME: find another way to pass this */
1132 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1133 : (NS_FACE_BACKGROUND (face) != 0
1134 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1135 : FRAME_BACKGROUND_COLOR (s->f)));
1137 /* render under GNUstep using DPS */
1138 #ifdef NS_IMPL_GNUSTEP
1140 NSGraphicsContext *context = GSCurrentContext ();
1145 /* do erase if "foreground" mode */
1149 DPSmoveto (context, r.origin.x, r.origin.y);
1150 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1151 DPSxshow (context, cbuf, advances, len);
1152 DPSstroke (context);
1154 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1158 if (face->underline_p)
1160 if (face->underline_color != 0)
1161 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1164 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1165 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1166 if (face->underline_color != 0)
1172 /* draw with DPSxshow () */
1173 DPSmoveto (context, r.origin.x, r.origin.y);
1174 DPSxshow (context, cbuf, advances, len);
1175 DPSstroke (context);
1177 DPSgrestore (context);
1181 #else /* NS_IMPL_COCOA */
1183 CGContextRef gcontext =
1184 [[NSGraphicsContext currentContext] graphicsPort];
1185 static CGAffineTransform fliptf;
1186 static BOOL firstTime = YES;
1191 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1194 CGContextSaveGState (gcontext);
1196 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1198 CGContextSetFont (gcontext, font->cgfont);
1199 CGContextSetFontSize (gcontext, font->size);
1200 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1201 CGContextSetShouldAntialias (gcontext, 0);
1203 CGContextSetShouldAntialias (gcontext, 1);
1204 if (EQ (ns_use_qd_smoothing, Qt))
1205 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1207 CGContextSetTextMatrix (gcontext, fliptf);
1211 /* foreground drawing; erase first to avoid overstrike */
1213 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1214 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1215 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1216 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1219 if (face->underline_p)
1221 if (face->underline_color != 0)
1222 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1225 CGContextBeginPath (gcontext);
1226 CGContextMoveToPoint (gcontext,
1227 r.origin.x, r.origin.y + font->underpos);
1228 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1229 r.origin.y + font->underpos);
1230 CGContextStrokePath (gcontext);
1231 if (face->underline_color != 0)
1237 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1238 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1241 if (face->overstrike)
1243 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1244 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1248 CGContextRestoreGState (gcontext);
1251 #endif /* NS_IMPL_COCOA */
1257 /* ==========================================================================
1259 Font glyph and metrics caching functions
1261 ========================================================================== */
1263 /* Find and cache corresponding glyph codes for unicode values in given
1264 hi-byte block of 256. */
1266 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1268 #ifdef NS_IMPL_COCOA
1269 static EmacsGlyphStorage *glyphStorage;
1270 static char firstTime = 1;
1272 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1273 unsigned int i, g, idx;
1274 unsigned short *glyphs;
1277 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1282 #ifdef NS_IMPL_COCOA
1286 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1290 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1291 if (!unichars || !(font_info->glyphs[block]))
1294 /* create a string containing all unicode characters in this block */
1295 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1296 if (idx < 0xD800 || idx > 0xDFFF)
1299 unichars[i] = 0xFEFF;
1300 unichars[0x100] = 0;
1303 #ifdef NS_IMPL_COCOA
1304 NSString *allChars = [[NSString alloc]
1305 initWithCharactersNoCopy: unichars
1308 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1309 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1310 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1311 unsigned int gInd =0, cInd =0;
1313 [glyphStorage setString: allChars font: font_info->nsfont];
1314 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1315 desiredNumberOfCharacters: glyphStorage->maxChar
1316 glyphIndex: &gInd characterIndex: &cInd];
1318 glyphs = font_info->glyphs[block];
1319 for (i =0; i<0x100; i++, glyphs++)
1321 #ifdef NS_IMPL_GNUSTEP
1324 g = glyphStorage->cglyphs[i];
1325 /* TODO: is this a good check? maybe need to use coveredChars.. */
1327 g = 0xFFFF; /* hopefully unused... */
1332 #ifdef NS_IMPL_COCOA
1342 /* Determine and cache metrics for corresponding glyph codes in given
1343 hi-byte block of 256. */
1345 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1348 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1350 struct font_metrics *metrics;
1353 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1356 #ifdef NS_IMPL_GNUSTEP
1357 /* not implemented yet (as of startup 0.18), so punt */
1359 numGlyphs = 0x10000;
1363 sfont = [font_info->nsfont screenFont];
1365 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1366 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1367 if (!(font_info->metrics[block]))
1370 metrics = font_info->metrics[block];
1371 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1374 NSRect r = [sfont boundingRectForGlyph: g];
1376 #ifdef NS_IMPL_GNUSTEP
1379 NSString *s = [NSString stringWithFormat: @"%c", g];
1380 w = [sfont widthOfString: s];
1383 w = [sfont advancementForGlyph: g].width;
1386 metrics->width = lrint (w);
1389 rb = r.size.width - w;
1391 metrics->lbearing = round (lb);
1392 if (font_info->ital)
1393 rb += 0.22 * font_info->height;
1394 metrics->rbearing = lrint (w + rb);
1396 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1397 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1398 metrics->ascent = r.size.height - metrics->descent;
1399 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1405 #ifdef NS_IMPL_COCOA
1406 /* helper for font glyph setup */
1407 @implementation EmacsGlyphStorage
1411 return [self initWithCapacity: 1024];
1414 - initWithCapacity: (unsigned long) c
1416 self = [super init];
1419 dict = [NSMutableDictionary new];
1420 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1433 - (void) setString: (NSString *)str font: (NSFont *)font
1435 [dict setObject: font forKey: NSFontAttributeName];
1436 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1437 maxChar = [str length];
1441 /* NSGlyphStorage protocol */
1442 - (unsigned int)layoutOptions
1447 - (NSAttributedString *)attributedString
1452 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1453 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1454 characterIndex: (unsigned int)charIndex
1456 len = glyphIndex+length;
1457 for (i =glyphIndex; i<len; i++)
1458 cglyphs[i] = glyphs[i-glyphIndex];
1463 - (void)setIntAttribute: (int)attributeTag value: (int)val
1464 forGlyphAtIndex: (unsigned)glyphIndex
1470 #endif /* NS_IMPL_COCOA */
1475 ns_dump_glyphstring (struct glyph_string *s)
1479 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1480 "overlap = %d, bg_filled = %d:",
1481 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1482 s->row->overlapping_p, s->background_filled_p);
1483 for (i =0; i<s->nchars; i++)
1484 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1485 fprintf (stderr, "\n");
1492 nsfont_driver.type = Qns;
1493 register_font_driver (&nsfont_driver, NULL);
1494 DEFSYM (Qapple, "apple");
1495 DEFSYM (Qroman, "roman");
1496 DEFSYM (Qmedium, "medium");
1499 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae