1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006-2012 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"
42 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
43 #ifdef NS_IMPL_GNUSTEP
44 #import <AppKit/NSFontDescriptor.h>
47 #define NSFONT_TRACE 0
49 extern Lisp_Object Qns;
50 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
51 static Lisp_Object Qapple, Qroman, Qmedium;
52 extern Lisp_Object Qappend;
53 extern float ns_antialias_threshold;
54 extern int ns_tmp_flags;
55 extern struct nsfont_info *ns_tmp_font;
57 /* font glyph and metrics caching functions, implemented at end */
58 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
60 static void ns_glyph_metrics (struct nsfont_info *font_info,
64 /* ==========================================================================
68 ========================================================================== */
71 /* Replace spaces w/another character so emacs core font parsing routines
74 ns_escape_name (char *name)
76 int i =0, len =strlen (name);
83 /* Reconstruct spaces in a font family name passed through emacs. */
85 ns_unescape_name (char *name)
87 int i =0, len =strlen (name);
94 /* Extract family name from a font spec. */
96 ns_get_family (Lisp_Object font_spec)
98 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
103 char *tmp = xstrdup (SDATA (SYMBOL_NAME (tem)));
105 ns_unescape_name (tmp);
106 family = [NSString stringWithUTF8String: tmp];
113 /* Return 0 if attr not set, else value (which might also be 0).
114 On Leopard 0 gets returned even on descriptors where the attribute
115 was never set, so there's no way to distinguish between unspecified
116 and set to not have. Callers should assume 0 means unspecified. */
118 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
120 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
121 NSNumber *val = [tdict objectForKey: trait];
122 return val == nil ? 0.0 : [val floatValue];
126 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
127 to NSFont descriptor. Information under extra only needed for matching. */
128 #define STYLE_REF 100
129 static NSFontDescriptor *
130 ns_spec_to_descriptor (Lisp_Object font_spec)
132 NSFontDescriptor *fdesc;
133 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
134 NSMutableDictionary *tdict = [NSMutableDictionary new];
135 NSString *family = ns_get_family (font_spec);
138 /* add each attr in font_spec to fdAttrs.. */
139 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
140 if (n != -1 && n != STYLE_REF)
141 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
142 forKey: NSFontWeightTrait];
143 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
144 if (n != -1 && n != STYLE_REF)
145 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
146 forKey: NSFontSlantTrait];
147 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
148 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
149 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
150 forKey: NSFontWidthTrait];
151 if ([tdict count] > 0)
152 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
154 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
157 fdesc = [fdesc fontDescriptorWithFamily: family];
166 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
168 ns_descriptor_to_entity (NSFontDescriptor *desc,
172 Lisp_Object font_entity = font_make_entity ();
173 /* NSString *psName = [desc postscriptName]; */
174 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
175 unsigned int traits = [desc symbolicTraits];
178 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
180 family = [desc objectForKey: NSFontNameAttribute];
182 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
184 escapedFamily = xstrdup ([family UTF8String]);
185 ns_escape_name (escapedFamily);
187 ASET (font_entity, FONT_TYPE_INDEX, Qns);
188 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
189 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
190 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
191 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
193 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
194 traits & NSFontBoldTrait ? Qbold : Qmedium);
195 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
196 make_number (100 + 100
197 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
198 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
199 traits & NSFontItalicTrait ? Qitalic : Qnormal);
200 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
201 make_number (100 + 100
202 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
203 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
204 traits & NSFontCondensedTrait ? Qcondensed :
205 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
206 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
207 make_number (100 + 100
208 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
210 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
211 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
212 ASET (font_entity, FONT_SPACING_INDEX,
213 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
214 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
216 ASET (font_entity, FONT_EXTRA_INDEX, extra);
217 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
221 fprintf (stderr, "created font_entity:\n ");
222 debug_print (font_entity);
225 xfree (escapedFamily);
230 /* Default font entity. */
232 ns_fallback_entity (void)
234 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
235 fontDescriptor], Qnil, NULL);
239 /* Utility: get width of a char c in screen font sfont */
241 ns_char_width (NSFont *sfont, int c)
244 NSString *cstr = [NSString stringWithFormat: @"%c", c];
246 NSGlyph glyph = [sfont glyphWithName: cstr];
249 float w = [sfont advancementForGlyph: glyph].width;
255 NSDictionary *attrsDictionary =
256 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
257 w = [cstr sizeWithAttributes: attrsDictionary].width;
263 /* Return whether set1 covers set2 to a reasonable extent given by pct.
264 We check, out of each 16 Unicode char range containing chars in set2,
265 whether at least one character is present in set1.
266 This must be true for pct of the pairs to consider it covering. */
268 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
270 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
271 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
272 int i, off = 0, tot = 0;
274 /* Work around what appears to be a GNUstep bug.
275 See <http://bugs.gnu.org/11853>. */
276 if (! (bytes1 && bytes2))
279 for (i=0; i<4096; i++, bytes1++, bytes2++)
283 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
286 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
287 return (float)off / tot < 1.0 - pct;
291 /* Convert :lang property to a script. Use of :lang property by font backend
292 seems to be limited for now (2009/05) to ja, zh, and ko. */
294 *ns_lang_to_script (Lisp_Object lang)
296 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
298 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
299 have more characters. */
300 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
302 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
309 /* Convert OTF 4-letter script code to emacs script name. (Why can't
310 everyone just use some standard Unicode names for these?) */
312 *ns_otf_to_script (Lisp_Object otf)
314 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
315 return CONSP (script)
316 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (XCDR ((script))))]
321 /* Convert a font registry, such as */
323 *ns_registry_to_script (char *reg)
325 Lisp_Object script, r, rts = Vns_reg_to_script;
328 r = XCAR (XCAR (rts));
329 if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
331 script = XCDR (XCAR (rts));
332 return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
340 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
341 plus registry regular property, for something that can be mapped to a
342 Unicode script. Empty string returned if no script spec found. */
344 *ns_get_req_script (Lisp_Object font_spec)
346 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
347 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
349 /* The extra-bundle properties have priority. */
350 for ( ; CONSP (extra); extra = XCDR (extra))
352 Lisp_Object tmp = XCAR (extra);
355 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
356 if (EQ (key, QCscript) && SYMBOLP (val))
357 return [NSString stringWithUTF8String:
358 SDATA (SYMBOL_NAME (val))];
359 if (EQ (key, QClang) && SYMBOLP (val))
360 return ns_lang_to_script (val);
361 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
362 return ns_otf_to_script (val);
366 /* If we get here, check the charset portion of the registry. */
369 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
370 (which causes box rendering if we don't treat it like iso8858-1)
371 but also for ascii (which causes unnecessary font substitution). */
373 if (EQ (reg, Qiso10646_1))
376 return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
383 /* This small function is static in fontset.c. If it can be made public for
384 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
386 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
388 if (EQ (XCAR (arg), val))
391 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
393 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
398 /* Use the Unicode range information in Vchar_script_table to convert a script
399 name into an NSCharacterSet. */
400 static NSCharacterSet
401 *ns_script_to_charset (NSString *scriptName)
403 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
404 Lisp_Object script = intern ([scriptName UTF8String]);
405 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
407 if (! NILP (Fmemq (script, script_list)))
409 Lisp_Object ranges, range_list;
411 ranges = Fcons (script, Qnil);
412 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
414 range_list = Fnreverse (XCDR (ranges));
415 if (! NILP (range_list))
417 for (; CONSP (range_list); range_list = XCDR (range_list))
419 int start = XINT (XCAR (XCAR (range_list)));
420 int end = XINT (XCDR (XCAR (range_list)));
422 debug_print (XCAR (range_list));
424 [charset addCharactersInRange:
425 NSMakeRange (start, end-start)];
433 /* Return an array of font families containing characters for the given
434 script, for the given coverage criterion, including at least LastResort.
435 Results are cached by script for faster access.
436 If none are found, we reduce the percentage and try again, until 5%.
437 This provides a font with at least some characters if such can be found.
438 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
439 (b) need approximate match as fonts covering full Unicode ranges are rare. */
441 *ns_get_covering_families (NSString *script, float pct)
443 static NSMutableDictionary *scriptToFamilies = nil;
444 NSMutableSet *families;
447 NSLog(@"Request covering families for script: '%@'", script);
449 if (scriptToFamilies == nil)
450 scriptToFamilies = [[NSMutableDictionary alloc] init];
452 if ((families = [scriptToFamilies objectForKey: script]) == nil)
454 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
455 NSArray *allFamilies = [fontMgr availableFontFamilies];
457 if ([script length] == 0)
458 families = [NSMutableSet setWithArray: allFamilies];
461 NSCharacterSet *charset = ns_script_to_charset (script);
463 families = [NSMutableSet setWithCapacity: 10];
466 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
467 while (family = [allFamiliesEnum nextObject])
469 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
470 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
471 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
473 fset = [NSCharacterSet characterSetWithRange:
474 NSMakeRange (0, 127)];
475 if (ns_charset_covers(fset, charset, pct))
476 [families addObject: family];
479 if ([families count] > 0 || pct < 0.05)
485 if ([families count] == 0)
486 [families addObject: @"LastResort"];
488 [scriptToFamilies setObject: families forKey: script];
492 NSLog(@" returning %d families", [families count]);
497 /* Implementation for list() and match(). List() can return nil, match()
498 must return something. Strategy is to drop family name from attribute
499 matching set for match. */
501 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
503 Lisp_Object tem, list = Qnil;
504 NSFontDescriptor *fdesc, *desc;
506 NSArray *matchingDescs;
514 fprintf (stderr, "nsfont: %s for fontspec:\n ",
515 (isMatch ? "match" : "list"));
516 debug_print (font_spec);
519 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
521 fdesc = ns_spec_to_descriptor (font_spec);
522 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
524 [fkeys removeObject: NSFontFamilyAttribute];
526 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
528 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
529 [matchingDescs count]);
531 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
533 if (![cFamilies containsObject:
534 [desc objectForKey: NSFontFamilyAttribute]])
536 tem = ns_descriptor_to_entity (desc,
537 AREF (font_spec, FONT_EXTRA_INDEX),
541 list = Fcons (tem, list);
542 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
546 /* Add synthItal member if needed. */
547 family = [fdesc objectForKey: NSFontFamilyAttribute];
548 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
550 NSFontDescriptor *s1 = [NSFontDescriptor new];
551 NSFontDescriptor *sDesc
552 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
553 fontDescriptorWithFamily: family];
554 list = Fcons (ns_descriptor_to_entity (sDesc,
555 AREF (font_spec, FONT_EXTRA_INDEX),
560 /* Return something if was a match and nothing found. */
562 return ns_fallback_entity ();
565 fprintf (stderr, " Returning %"pI"d entities.\n",
566 XINT (Flength (list)));
573 /* ==========================================================================
575 Font driver implementation
577 ========================================================================== */
580 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
581 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
582 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
583 static Lisp_Object nsfont_list_family (Lisp_Object frame);
584 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
586 static void nsfont_close (FRAME_PTR f, struct font *font);
587 static int nsfont_has_char (Lisp_Object entity, int c);
588 static unsigned int nsfont_encode_char (struct font *font, int c);
589 static int nsfont_text_extents (struct font *font, unsigned int *code,
590 int nglyphs, struct font_metrics *metrics);
591 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
592 int with_background);
594 struct font_driver nsfont_driver =
597 1, /* case sensitive */
602 NULL, /*free_entity */
605 NULL, /* prepare_face */
606 NULL, /* done_face */
611 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
612 anchor_point, otf_capability, otf_driver,
613 start_for_frame, end_for_frame, shape */
617 /* Return a cache of font-entities on FRAME. The cache must be a
618 cons whose cdr part is the actual cache area. */
620 nsfont_get_cache (FRAME_PTR frame)
622 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
623 return (dpyinfo->name_list_element);
627 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
628 **list** of font-entities. This and match () are sole APIs that allocate
629 font-entities. Properties to be considered (2009/05/19) are:
630 regular: foundry, family, adstyle, registry
631 extended: script, lang, otf
632 "Extended" properties are not part of the vector but get stored as
633 lisp properties under FONT_EXTRA_INDEX.
635 The returned entities should have type set (to 'ns), plus the following:
636 foundry, family, adstyle, registry,
637 weight, slant, width, size (0 if scalable),
638 dpi, spacing, avgwidth (0 if scalable) */
640 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
642 return ns_findfonts (font_spec, NO);
646 /* Return a font entity most closely matching with FONT_SPEC on
647 FRAME. The closeness is determined by the font backend, thus
648 `face-font-selection-order' is ignored here.
649 Properties to be considered are same as for list(). */
651 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
653 return ns_findfonts(font_spec, YES);
657 /* List available families. The value is a list of family names
660 nsfont_list_family (Lisp_Object frame)
662 Lisp_Object list = Qnil;
663 NSEnumerator *families =
664 [[[NSFontManager sharedFontManager] availableFontFamilies]
667 while (family = [families nextObject])
668 list = Fcons (intern ([family UTF8String]), list);
669 /* FIXME: escape the name? */
672 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
673 XINT (Flength (list)));
679 /* Open a font specified by FONT_ENTITY on frame F. If the font is
680 scalable, open it with PIXEL_SIZE. */
682 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
685 unsigned int traits = 0;
686 struct nsfont_info *font_info;
688 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
689 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
691 NSFont *nsfont, *sfont;
694 Lisp_Object font_object;
697 static NSMutableDictionary *fontCache = nil;
700 /* 2008/03/08: The same font may end up being requested for different
701 entities, due to small differences in numeric values or other issues,
702 or for different copies of the same entity. Therefore we cache to
703 avoid creating multiple struct font objects (with metrics cache, etc.)
704 for the same NSFont object. */
705 if (fontCache == nil)
706 fontCache = [[NSMutableDictionary alloc] init];
710 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
711 debug_print (font_entity);
716 /* try to get it out of frame params */
717 Lisp_Object tem = get_frame_param (f, Qfontsize);
718 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
721 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
722 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
724 family = ns_get_family (font_entity);
726 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
727 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
728 when setting family in ns_spec_to_descriptor(). */
729 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
730 traits |= NSBoldFontMask;
731 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
732 traits |= NSItalicFontMask;
734 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
735 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
736 nsfont = [fontMgr fontWithFamily: family
737 traits: traits weight: fixLeopardBug
739 /* if didn't find, try synthetic italic */
740 if (nsfont == nil && synthItal)
742 nsfont = [fontMgr fontWithFamily: family
743 traits: traits & ~NSItalicFontMask
744 weight: fixLeopardBug size: pixel_size];
747 /* LastResort not really a family */
748 if (nsfont == nil && [@"LastResort" isEqualToString: family])
749 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
754 message_with_string ("*** Warning: font in family '%s' not found",
755 build_string ([family UTF8String]), 1);
756 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
760 NSLog (@"%@\n", nsfont);
762 /* Check the cache */
763 cached = [fontCache objectForKey: nsfont];
764 if (cached != nil && !synthItal)
767 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
768 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
769 XHASH (font_object) = [cached unsignedLongValue];
774 font_object = font_make_object (VECSIZE (struct nsfont_info),
775 font_entity, pixel_size);
777 [fontCache setObject: [NSNumber numberWithUnsignedLong:
778 (unsigned long) XHASH (font_object)]
782 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
783 font = (struct font *) font_info;
785 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
787 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
788 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
793 sfont = [nsfont screenFont];
797 /* non-metric backend font struct fields */
798 font = (struct font *) font_info;
799 font->pixel_size = [sfont pointSize];
800 font->driver = &nsfont_driver;
801 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
802 font->encoding_charset = -1;
803 font->repertory_charset = -1;
804 font->default_ascent = 0;
805 font->vertical_centering = 0;
806 font->baseline_offset = 0;
807 font->relative_compose = 0;
808 font->font_encoder = NULL;
810 font->props[FONT_FORMAT_INDEX] = Qns;
811 font->props[FONT_FILE_INDEX] = Qnil;
814 const char *fontName = [[nsfont fontName] UTF8String];
815 int len = strlen (fontName);
817 /* The values specified by fonts are not always exact. For
818 * example, a 6x8 font could specify that the descender is
819 * -2.00000405... (represented by 0xc000000220000000). Without
820 * adjustment, the code below would round the descender to -3,
821 * resulting in a font that would be one pixel higher than
823 CGFloat adjusted_descender = [sfont descender] + 0.0001;
825 #ifdef NS_IMPL_GNUSTEP
826 font_info->nsfont = sfont;
828 font_info->nsfont = nsfont;
830 [font_info->nsfont retain];
832 /* set up ns_font (defined in nsgui.h) */
833 font_info->name = xstrdup (fontName);
834 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
836 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
838 /* Metrics etc.; some fonts return an unusually large max advance, so we
839 only use it for fonts that have wide characters. */
840 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
841 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
843 brect = [sfont boundingRectForFont];
845 font_info->underpos = [sfont underlinePosition];
846 font_info->underwidth = [sfont underlineThickness];
847 font_info->size = font->pixel_size;
850 font_info->max_bounds.ascent = lrint ([sfont ascender]);
851 /* Descender is usually negative. Use floor to avoid
852 clipping descenders. */
853 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
855 font_info->max_bounds.ascent + font_info->max_bounds.descent;
856 font_info->max_bounds.width = lrint (font_info->width);
857 font_info->max_bounds.lbearing = lrint (brect.origin.x);
858 font_info->max_bounds.rbearing =
859 lrint (brect.size.width - font_info->width);
862 /* set up synthItal and the CG font */
863 font_info->synthItal = synthItal;
865 ATSFontRef atsFont = ATSFontFindFromPostScriptName
866 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
868 if (atsFont == kATSFontRefUnspecified)
870 /* see if we can get it by dropping italic (then synthesizing) */
871 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
872 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
873 fontName], kATSOptionFlagsDefault);
874 if (atsFont != kATSFontRefUnspecified)
875 font_info->synthItal = YES;
878 /* last resort fallback */
879 atsFont = ATSFontFindFromPostScriptName
880 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
883 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
887 /* set up metrics portion of font struct */
888 font->ascent = lrint([sfont ascender]);
889 font->descent = -lrint(floor(adjusted_descender));
890 font->min_width = ns_char_width(sfont, '|');
891 font->space_width = lrint (ns_char_width (sfont, ' '));
892 font->average_width = lrint (font_info->width);
893 font->max_width = lrint (font_info->max_bounds.width);
894 font->height = lrint (font_info->height);
895 font->underline_position = lrint (font_info->underpos);
896 font->underline_thickness = lrint (font_info->underwidth);
898 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
899 font->props[FONT_FULLNAME_INDEX] =
900 make_unibyte_string (font_info->name, strlen (font_info->name));
908 /* Close FONT on frame F. */
910 nsfont_close (FRAME_PTR f, struct font *font)
912 struct nsfont_info *font_info = (struct nsfont_info *)font;
915 /* FIXME: this occurs apparently due to same failure to detect same font
916 that causes need for cache in nsfont_open () */
920 for (i =0; i<0x100; i++)
922 xfree (font_info->glyphs[i]);
923 xfree (font_info->metrics[i]);
925 [font_info->nsfont release];
927 CGFontRelease (font_info->cgfont);
929 xfree (font_info->name);
934 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
935 return 1. If not, return 0. If a font must be opened to check
938 nsfont_has_char (Lisp_Object entity, int c)
944 /* Return a glyph code of FONT for character C (Unicode code point).
945 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
947 nsfont_encode_char (struct font *font, int c)
949 struct nsfont_info *font_info = (struct nsfont_info *)font;
950 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
954 return FONT_INVALID_CODE;
956 /* did we already cache this block? */
957 if (!font_info->glyphs[high])
958 ns_uni_to_glyphs (font_info, high);
960 g = font_info->glyphs[high][low];
961 return g == 0xFFFF ? FONT_INVALID_CODE : g;
965 /* Perform the size computation of glyphs of FONT and fill in members
966 of METRICS. The glyphs are specified by their glyph codes in
967 CODE (length NGLYPHS). */
969 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
970 struct font_metrics *metrics)
972 struct nsfont_info *font_info = (struct nsfont_info *)font;
973 struct font_metrics *pcm;
974 unsigned char high, low;
978 memset (metrics, 0, sizeof (struct font_metrics));
980 for (i =0; i<nglyphs; i++)
982 /* get metrics for this glyph, filling cache if need be */
983 /* TODO: get metrics for whole string from an NSLayoutManager
985 high = (code[i] & 0xFF00) >> 8;
986 low = code[i] & 0x00FF;
987 if (!font_info->metrics[high])
988 ns_glyph_metrics (font_info, high);
989 pcm = &(font_info->metrics[high][low]);
991 if (metrics->lbearing > totalWidth + pcm->lbearing)
992 metrics->lbearing = totalWidth + pcm->lbearing;
993 if (metrics->rbearing < totalWidth + pcm->rbearing)
994 metrics->rbearing = totalWidth + pcm->rbearing;
995 if (metrics->ascent < pcm->ascent)
996 metrics->ascent = pcm->ascent;
997 if (metrics->descent < pcm->descent)
998 metrics->descent = pcm->descent;
1000 totalWidth += pcm->width;
1003 metrics->width = totalWidth;
1005 return totalWidth; /* not specified in doc, but xfont.c does it */
1009 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1010 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
1011 is nonzero, fill the background in advance. It is assured that
1012 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1014 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1015 int with_background)
1016 /* NOTE: focus and clip must be set
1017 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1019 static char cbuf[1024];
1021 #ifdef NS_IMPL_GNUSTEP
1022 static float advances[1024];
1023 float *adv = advances;
1025 static CGSize advances[1024];
1026 CGSize *adv = advances;
1030 struct nsfont_info *font = ns_tmp_font;
1031 NSColor *col, *bgCol;
1032 unsigned short *t = s->char2b;
1034 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1035 int end = isComposite ? s->cmp_to : s->nchars;
1037 /* Select face based on input flags */
1038 switch (ns_tmp_flags)
1040 case NS_DUMPGLYPH_CURSOR:
1043 case NS_DUMPGLYPH_MOUSEFACE:
1044 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1046 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1053 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1054 r.origin.x += abs (s->face->box_line_width);
1057 r.size.height = FONT_HEIGHT (font);
1059 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1060 NS to render the string, it will come out differently from the individual
1061 character widths added up because of layout processing. */
1064 int cwidth, twidth = 0;
1066 /* FIXME: composition: no vertical displacement is considered. */
1067 t += s->cmp_from; /* advance into composition */
1068 for (i = s->cmp_from; i < end; i++, t++)
1070 hi = (*t & 0xFF00) >> 8;
1074 if (!s->first_glyph->u.cmp.automatic)
1075 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1078 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1079 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1080 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1081 cwidth = LGLYPH_WIDTH (glyph);
1084 cwidth = LGLYPH_WADJUST (glyph);
1085 #ifdef NS_IMPL_GNUSTEP
1086 *(adv-1) += LGLYPH_XOFF (glyph);
1088 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1095 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1096 ns_glyph_metrics (font, hi);
1097 cwidth = font->metrics[hi][lo].width;
1100 #ifdef NS_IMPL_GNUSTEP
1102 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1104 (*adv++).width = cwidth;
1107 len = adv - advances;
1108 r.size.width = twidth;
1112 /* fill background if requested */
1113 if (with_background && !isComposite)
1116 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1117 int mbox_line_width = max (s->face->box_line_width, 0);
1119 if (s->row->full_width_p)
1121 if (br.origin.x <= fibw + 1 + mbox_line_width)
1123 br.size.width += br.origin.x - mbox_line_width;
1124 br.origin.x = mbox_line_width;
1126 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1128 br.size.width += fibw;
1130 if (s->face->box == FACE_NO_BOX)
1132 /* expand unboxed top row over internal border */
1133 if (br.origin.y <= fibw + 1 + mbox_line_width)
1135 br.size.height += br.origin.y;
1141 int correction = abs (s->face->box_line_width)+1;
1142 br.origin.y += correction;
1143 br.size.height -= 2*correction;
1144 br.origin.x += correction;
1145 br.size.width -= 2*correction;
1148 if (!s->face->stipple)
1149 [(NS_FACE_BACKGROUND (face) != 0
1150 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1151 : FRAME_BACKGROUND_COLOR (s->f)) set];
1154 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1155 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1161 /* set up for character rendering */
1162 r.origin.y = s->ybase;
1164 col = (NS_FACE_FOREGROUND (face) != 0
1165 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1166 : FRAME_FOREGROUND_COLOR (s->f));
1167 /* FIXME: find another way to pass this */
1168 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1169 : (NS_FACE_BACKGROUND (face) != 0
1170 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1171 : FRAME_BACKGROUND_COLOR (s->f)));
1173 /* render under GNUstep using DPS */
1174 #ifdef NS_IMPL_GNUSTEP
1176 NSGraphicsContext *context = GSCurrentContext ();
1181 /* do erase if "foreground" mode */
1185 DPSmoveto (context, r.origin.x, r.origin.y);
1186 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1187 DPSxshow (context, cbuf, advances, len);
1188 DPSstroke (context);
1190 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1195 /* draw with DPSxshow () */
1196 DPSmoveto (context, r.origin.x, r.origin.y);
1197 DPSxshow (context, cbuf, advances, len);
1198 DPSstroke (context);
1200 DPSgrestore (context);
1203 #else /* NS_IMPL_COCOA */
1205 CGContextRef gcontext =
1206 [[NSGraphicsContext currentContext] graphicsPort];
1207 static CGAffineTransform fliptf;
1208 static BOOL firstTime = YES;
1213 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1216 CGContextSaveGState (gcontext);
1218 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1220 CGContextSetFont (gcontext, font->cgfont);
1221 CGContextSetFontSize (gcontext, font->size);
1222 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1223 CGContextSetShouldAntialias (gcontext, 0);
1225 CGContextSetShouldAntialias (gcontext, 1);
1227 CGContextSetTextMatrix (gcontext, fliptf);
1231 /* foreground drawing; erase first to avoid overstrike */
1233 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1234 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1235 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1236 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1241 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1242 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1245 if (face->overstrike)
1247 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1248 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1252 CGContextRestoreGState (gcontext);
1254 #endif /* NS_IMPL_COCOA */
1256 /* Draw underline, overline, strike-through. */
1257 ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1264 /* ==========================================================================
1266 Font glyph and metrics caching functions
1268 ========================================================================== */
1270 /* Find and cache corresponding glyph codes for unicode values in given
1271 hi-byte block of 256. */
1273 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1275 #ifdef NS_IMPL_COCOA
1276 static EmacsGlyphStorage *glyphStorage;
1277 static char firstTime = 1;
1279 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1280 unsigned int i, g, idx;
1281 unsigned short *glyphs;
1284 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1289 #ifdef NS_IMPL_COCOA
1293 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1297 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1298 if (!unichars || !(font_info->glyphs[block]))
1301 /* create a string containing all Unicode characters in this block */
1302 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1303 if (idx < 0xD800 || idx > 0xDFFF)
1306 unichars[i] = 0xFEFF;
1307 unichars[0x100] = 0;
1310 #ifdef NS_IMPL_COCOA
1311 NSString *allChars = [[NSString alloc]
1312 initWithCharactersNoCopy: unichars
1315 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1316 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1317 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1318 NSUInteger gInd = 0, cInd = 0;
1320 [glyphStorage setString: allChars font: font_info->nsfont];
1321 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1322 desiredNumberOfCharacters: glyphStorage->maxChar
1323 glyphIndex: &gInd characterIndex: &cInd];
1325 glyphs = font_info->glyphs[block];
1326 for (i = 0; i < 0x100; i++, glyphs++)
1328 #ifdef NS_IMPL_GNUSTEP
1331 g = glyphStorage->cglyphs[i];
1332 /* TODO: is this a good check? maybe need to use coveredChars.. */
1334 g = 0xFFFF; /* hopefully unused... */
1339 #ifdef NS_IMPL_COCOA
1349 /* Determine and cache metrics for corresponding glyph codes in given
1350 hi-byte block of 256. */
1352 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1355 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1357 struct font_metrics *metrics;
1360 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1363 #ifdef NS_IMPL_GNUSTEP
1364 /* not implemented yet (as of startup 0.18), so punt */
1366 numGlyphs = 0x10000;
1370 sfont = [font_info->nsfont screenFont];
1372 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1373 if (!(font_info->metrics[block]))
1376 metrics = font_info->metrics[block];
1377 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1380 NSRect r = [sfont boundingRectForGlyph: g];
1382 w = max ([sfont advancementForGlyph: g].width, 2.0);
1383 metrics->width = lrint (w);
1386 rb = r.size.width - w;
1388 metrics->lbearing = round (lb);
1389 if (font_info->ital)
1390 rb += 0.22 * font_info->height;
1391 metrics->rbearing = lrint (w + rb);
1393 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1394 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1395 metrics->ascent = r.size.height - metrics->descent;
1396 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1402 #ifdef NS_IMPL_COCOA
1403 /* helper for font glyph setup */
1404 @implementation EmacsGlyphStorage
1408 return [self initWithCapacity: 1024];
1411 - initWithCapacity: (unsigned long) c
1413 self = [super init];
1416 dict = [NSMutableDictionary new];
1417 cglyphs = xmalloc (c * sizeof (CGGlyph));
1430 - (void) setString: (NSString *)str font: (NSFont *)font
1432 [dict setObject: font forKey: NSFontAttributeName];
1435 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1436 maxChar = [str length];
1440 /* NSGlyphStorage protocol */
1441 - (NSUInteger)layoutOptions
1446 - (NSAttributedString *)attributedString
1451 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1452 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1453 characterIndex: (NSUInteger)charIndex
1455 len = glyphIndex+length;
1456 for (i =glyphIndex; i<len; i++)
1457 cglyphs[i] = glyphs[i-glyphIndex];
1462 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1463 forGlyphAtIndex: (NSUInteger)glyphIndex
1469 #endif /* NS_IMPL_COCOA */
1474 ns_dump_glyphstring (struct glyph_string *s)
1478 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1479 "overlap = %d, bg_filled = %d:",
1480 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1481 s->row->overlapping_p, s->background_filled_p);
1482 for (i =0; i<s->nchars; i++)
1483 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1484 fprintf (stderr, "\n");
1489 syms_of_nsfont (void)
1491 nsfont_driver.type = Qns;
1492 register_font_driver (&nsfont_driver, NULL);
1493 DEFSYM (Qapple, "apple");
1494 DEFSYM (Qroman, "roman");
1495 DEFSYM (Qmedium, "medium");
1496 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1497 doc: /* Internal use: maps font registry to Unicode script. */);