1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 2006-2011 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 = strdup (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];
156 fdesc = [fdesc fontDescriptorWithFamily: family];
161 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
163 ns_descriptor_to_entity (NSFontDescriptor *desc,
167 Lisp_Object font_entity = font_make_entity ();
168 /* NSString *psName = [desc postscriptName]; */
169 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
170 unsigned int traits = [desc symbolicTraits];
173 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
175 family = [desc objectForKey: NSFontNameAttribute];
177 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
179 escapedFamily = strdup ([family UTF8String]);
180 ns_escape_name (escapedFamily);
182 ASET (font_entity, FONT_TYPE_INDEX, Qns);
183 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
184 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
185 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
186 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
188 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
189 traits & NSFontBoldTrait ? Qbold : Qmedium);
190 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
191 make_number (100 + 100
192 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
193 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
194 traits & NSFontItalicTrait ? Qitalic : Qnormal);
195 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
196 make_number (100 + 100
197 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
198 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
199 traits & NSFontCondensedTrait ? Qcondensed :
200 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
201 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
202 make_number (100 + 100
203 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
205 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
206 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
207 ASET (font_entity, FONT_SPACING_INDEX,
208 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
209 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
211 ASET (font_entity, FONT_EXTRA_INDEX, extra);
212 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
216 fprintf (stderr, "created font_entity:\n ");
217 debug_print (font_entity);
220 free (escapedFamily);
225 /* Default font entity. */
227 ns_fallback_entity (void)
229 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
230 fontDescriptor], Qnil, NULL);
234 /* Utility: get width of a char c in screen font sfont */
236 ns_char_width (NSFont *sfont, int c)
239 NSString *cstr = [NSString stringWithFormat: @"%c", c];
241 NSGlyph glyph = [sfont glyphWithName: cstr];
244 float w = [sfont advancementForGlyph: glyph].width;
250 NSDictionary *attrsDictionary =
251 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
252 w = [cstr sizeWithAttributes: attrsDictionary].width;
258 /* Return whether set1 covers set2 to a reasonable extent given by pct.
259 We check, out of each 16 unicode char range containing chars in set2,
260 whether at least one character is present in set1.
261 This must be true for pct of the pairs to consider it covering. */
263 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
265 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
266 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
267 int i, off = 0, tot = 0;
269 for (i=0; i<4096; i++, bytes1++, bytes2++)
273 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
276 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
277 return (float)off / tot < 1.0 - pct;
281 /* Convert :lang property to a script. Use of :lang property by font backend
282 seems to be limited for now (2009/05) to ja, zh, and ko. */
284 *ns_lang_to_script (Lisp_Object lang)
286 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
288 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
289 have more characters. */
290 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
292 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
299 /* Convert OTF 4-letter script code to emacs script name. (Why can't
300 everyone just use some standard unicode names for these?) */
302 *ns_otf_to_script (Lisp_Object otf)
304 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
305 return CONSP (script)
306 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
311 /* Convert a font registry, such as */
313 *ns_registry_to_script (char *reg)
315 Lisp_Object script, r, rts = Vns_reg_to_script;
318 r = XCAR (XCAR (rts));
319 if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
321 script = XCDR (XCAR (rts));
322 return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
330 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
331 plus registry regular property, for something that can be mapped to a
332 unicode script. Empty string returned if no script spec found. */
334 *ns_get_req_script (Lisp_Object font_spec)
336 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
337 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
339 /* The extra-bundle properties have priority. */
340 for ( ; CONSP (extra); extra = XCDR (extra))
342 Lisp_Object tmp = XCAR (extra);
345 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
346 if (EQ (key, QCscript) && SYMBOLP (val))
347 return [NSString stringWithUTF8String:
348 SDATA (SYMBOL_NAME (val))];
349 if (EQ (key, QClang) && SYMBOLP (val))
350 return ns_lang_to_script (val);
351 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
352 return ns_otf_to_script (val);
356 /* If we get here, check the charset portion of the registry. */
359 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
360 (which causes box rendering if we don't treat it like iso8858-1)
361 but also for ascii (which causes unnecessary font substitution). */
363 if (EQ (reg, Qiso10646_1))
366 return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
373 /* This small function is static in fontset.c. If it can be made public for
374 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
376 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
378 if (EQ (XCAR (arg), val))
381 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
383 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
388 /* Use the unicode range information in Vchar_script_table to convert a script
389 name into an NSCharacterSet. */
390 static NSCharacterSet
391 *ns_script_to_charset (NSString *scriptName)
393 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
394 Lisp_Object script = intern ([scriptName UTF8String]);
395 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
397 if (! NILP (Fmemq (script, script_list)))
399 Lisp_Object ranges, range_list;
401 ranges = Fcons (script, Qnil);
402 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
404 range_list = Fnreverse (XCDR (ranges));
405 if (! NILP (range_list))
407 for (; CONSP (range_list); range_list = XCDR (range_list))
409 int start = XINT (XCAR (XCAR (range_list)));
410 int end = XINT (XCDR (XCAR (range_list)));
412 debug_print (XCAR (range_list));
414 [charset addCharactersInRange:
415 NSMakeRange (start, end-start)];
423 /* Return an array of font families containing characters for the given
424 script, for the given coverage criterion, including at least LastResort.
425 Results are cached by script for faster access.
426 If none are found, we reduce the percentage and try again, until 5%.
427 This provides a font with at least some characters if such can be found.
428 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
429 (b) need approximate match as fonts covering full unicode ranges are rare. */
431 *ns_get_covering_families (NSString *script, float pct)
433 static NSMutableDictionary *scriptToFamilies = nil;
434 NSMutableSet *families;
437 NSLog(@"Request covering families for script: '%@'", script);
439 if (scriptToFamilies == nil)
440 scriptToFamilies = [[NSMutableDictionary alloc] init];
442 if ((families = [scriptToFamilies objectForKey: script]) == nil)
444 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
445 NSArray *allFamilies = [fontMgr availableFontFamilies];
447 if ([script length] == 0)
448 families = [NSMutableSet setWithArray: allFamilies];
451 NSCharacterSet *charset = ns_script_to_charset (script);
453 families = [NSMutableSet setWithCapacity: 10];
456 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
457 while (family = [allFamiliesEnum nextObject])
459 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
460 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
461 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
463 fset = [NSCharacterSet characterSetWithRange:
464 NSMakeRange (0, 127)];
465 if (ns_charset_covers(fset, charset, pct))
466 [families addObject: family];
469 if ([families count] > 0 || pct < 0.05)
474 if ([families count] == 0)
475 [families addObject: @"LastResort"];
477 [scriptToFamilies setObject: families forKey: script];
481 NSLog(@" returning %d families", [families count]);
486 /* Implementation for list() and match(). List() can return nil, match()
487 must return something. Strategy is to drop family name from attribute
488 matching set for match. */
490 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
492 Lisp_Object tem, list = Qnil;
493 NSFontDescriptor *fdesc, *desc;
495 NSArray *matchingDescs;
503 fprintf (stderr, "nsfont: %s for fontspec:\n ",
504 (isMatch ? "match" : "list"));
505 debug_print (font_spec);
508 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
510 fdesc = ns_spec_to_descriptor (font_spec);
511 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
513 [fkeys removeObject: NSFontFamilyAttribute];
515 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
517 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
518 [matchingDescs count]);
520 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
522 if (![cFamilies containsObject:
523 [desc objectForKey: NSFontFamilyAttribute]])
525 tem = ns_descriptor_to_entity (desc,
526 AREF (font_spec, FONT_EXTRA_INDEX),
530 list = Fcons (tem, list);
531 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
535 /* Add synthItal member if needed. */
536 family = [fdesc objectForKey: NSFontFamilyAttribute];
537 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
539 NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
540 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
541 fontDescriptorWithFamily: family];
542 list = Fcons (ns_descriptor_to_entity (sDesc,
543 AREF (font_spec, FONT_EXTRA_INDEX),
547 /* Return something if was a match and nothing found. */
549 return ns_fallback_entity ();
552 fprintf (stderr, " Returning %ld entities.\n",
553 (long) XINT (Flength (list)));
560 /* ==========================================================================
562 Font driver implementation
564 ========================================================================== */
567 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
568 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
569 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
570 static Lisp_Object nsfont_list_family (Lisp_Object frame);
571 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
573 static void nsfont_close (FRAME_PTR f, struct font *font);
574 static int nsfont_has_char (Lisp_Object entity, int c);
575 static unsigned int nsfont_encode_char (struct font *font, int c);
576 static int nsfont_text_extents (struct font *font, unsigned int *code,
577 int nglyphs, struct font_metrics *metrics);
578 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
579 int with_background);
581 struct font_driver nsfont_driver =
584 1, /* case sensitive */
589 NULL, /*free_entity */
592 NULL, /* prepare_face */
593 NULL, /* done_face */
598 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
599 anchor_point, otf_capability, otf_driver,
600 start_for_frame, end_for_frame, shape */
604 /* Return a cache of font-entities on FRAME. The cache must be a
605 cons whose cdr part is the actual cache area. */
607 nsfont_get_cache (FRAME_PTR frame)
609 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
610 return (dpyinfo->name_list_element);
614 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
615 **list** of font-entities. This and match () are sole APIs that allocate
616 font-entities. Properties to be considered (2009/05/19) are:
617 regular: foundry, family, adstyle, registry
618 extended: script, lang, otf
619 "Extended" properties are not part of the vector but get stored as
620 lisp properties under FONT_EXTRA_INDEX.
622 The returned entities should have type set (to 'ns), plus the following:
623 foundry, family, adstyle, registry,
624 weight, slant, width, size (0 if scalable),
625 dpi, spacing, avgwidth (0 if scalable) */
627 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
629 return ns_findfonts (font_spec, NO);
633 /* Return a font entity most closely maching with FONT_SPEC on
634 FRAME. The closeness is determined by the font backend, thus
635 `face-font-selection-order' is ignored here.
636 Properties to be considered are same as for list(). */
638 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
640 return ns_findfonts(font_spec, YES);
644 /* List available families. The value is a list of family names
647 nsfont_list_family (Lisp_Object frame)
649 Lisp_Object list = Qnil;
650 NSEnumerator *families =
651 [[[NSFontManager sharedFontManager] availableFontFamilies]
654 while (family = [families nextObject])
655 list = Fcons (intern ([family UTF8String]), list);
656 /* FIXME: escape the name? */
659 fprintf (stderr, "nsfont: list families returning %ld entries\n",
660 (long) XINT (Flength (list)));
666 /* Open a font specified by FONT_ENTITY on frame F. If the font is
667 scalable, open it with PIXEL_SIZE. */
669 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
672 unsigned int traits = 0;
673 struct nsfont_info *font_info;
675 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
676 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
678 NSFont *nsfont, *sfont;
681 Lisp_Object font_object;
684 static NSMutableDictionary *fontCache = nil;
687 /* 2008/03/08: The same font may end up being requested for different
688 entities, due to small differences in numeric values or other issues,
689 or for different copies of the same entity. Therefore we cache to
690 avoid creating multiple struct font objects (with metrics cache, etc.)
691 for the same NSFont object. */
692 if (fontCache == nil)
693 fontCache = [[NSMutableDictionary alloc] init];
697 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
698 debug_print (font_entity);
703 /* try to get it out of frame params */
704 Lisp_Object tem = get_frame_param (f, Qfontsize);
705 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
708 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
709 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
711 family = ns_get_family (font_entity);
713 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
714 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
715 when setting family in ns_spec_to_descriptor(). */
716 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
717 traits |= NSBoldFontMask;
718 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
719 traits |= NSItalicFontMask;
721 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
722 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
723 nsfont = [fontMgr fontWithFamily: family
724 traits: traits weight: fixLeopardBug
726 /* if didn't find, try synthetic italic */
727 if (nsfont == nil && synthItal)
729 nsfont = [fontMgr fontWithFamily: family
730 traits: traits & ~NSItalicFontMask
731 weight: fixLeopardBug size: pixel_size];
734 /* LastResort not really a family */
735 if (nsfont == nil && [@"LastResort" isEqualToString: family])
736 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
741 message_with_string ("*** Warning: font in family '%s' not found",
742 build_string ([family UTF8String]), 1);
743 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
747 NSLog (@"%@\n", nsfont);
749 /* Check the cache */
750 cached = [fontCache objectForKey: nsfont];
751 if (cached != nil && !synthItal)
754 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
755 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
756 XHASH (font_object) = [cached unsignedLongValue];
761 font_object = font_make_object (VECSIZE (struct nsfont_info),
762 font_entity, pixel_size);
764 [fontCache setObject: [NSNumber numberWithUnsignedLong:
765 (unsigned long) XHASH (font_object)]
769 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
770 font = (struct font *) font_info;
772 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
774 font_info->glyphs = (unsigned short **)
775 xmalloc (0x100 * sizeof (unsigned short *));
776 font_info->metrics = (struct font_metrics **)
777 xmalloc (0x100 * sizeof (struct font_metrics *));
778 if (!font_info->glyphs || !font_info->metrics)
780 memset (font_info->glyphs, 0, 0x100 * sizeof (unsigned short *));
781 memset (font_info->metrics, 0, 0x100 * sizeof (struct font_metrics *));
786 sfont = [nsfont screenFont];
790 /* non-metric backend font struct fields */
791 font = (struct font *) font_info;
792 font->pixel_size = [sfont pointSize];
793 font->driver = &nsfont_driver;
794 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
795 font->encoding_charset = -1;
796 font->repertory_charset = -1;
797 font->default_ascent = 0;
798 font->vertical_centering = 0;
799 font->baseline_offset = 0;
800 font->relative_compose = 0;
801 font->font_encoder = NULL;
803 font->props[FONT_FORMAT_INDEX] = Qns;
804 font->props[FONT_FILE_INDEX] = Qnil;
807 double expand, hshrink;
808 float full_height, min_height, hd;
809 const char *fontName = [[nsfont fontName] UTF8String];
810 int len = strlen (fontName);
812 /* The values specified by fonts are not always exact. For
813 * example, a 6x8 font could specify that the descender is
814 * -2.00000405... (represented by 0xc000000220000000). Without
815 * adjustment, the code below would round the descender to -3,
816 * resulting in a font that would be one pixel higher than
818 CGFloat adjusted_descender = [sfont descender] + 0.0001;
820 #ifdef NS_IMPL_GNUSTEP
821 font_info->nsfont = sfont;
823 font_info->nsfont = nsfont;
825 [font_info->nsfont retain];
827 /* set up ns_font (defined in nsgui.h) */
828 font_info->name = (char *)xmalloc (strlen (fontName)+1);
829 strcpy (font_info->name, fontName);
830 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
832 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
834 /* Metrics etc.; some fonts return an unusually large max advance, so we
835 only use it for fonts that have wide characters. */
836 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
837 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
839 brect = [sfont boundingRectForFont];
840 full_height = brect.size.height;
841 min_height = [sfont ascender] - adjusted_descender;
842 hd = full_height - min_height;
844 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
848 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
849 font_info->underwidth = [sfont underlineThickness];
850 font_info->size = font->pixel_size;
851 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
854 font_info->max_bounds.ascent =
855 lrint (hshrink * [sfont ascender] + expand * hd/2);
856 /* Descender is usually negative. Use floor to avoid
857 clipping descenders. */
858 font_info->max_bounds.descent =
859 -lrint (floor(hshrink* adjusted_descender - expand*hd/2));
861 font_info->max_bounds.ascent + font_info->max_bounds.descent;
862 font_info->max_bounds.width = lrint (font_info->width);
863 font_info->max_bounds.lbearing = lrint (brect.origin.x);
864 font_info->max_bounds.rbearing =
865 lrint (brect.size.width - font_info->width);
868 /* set up synthItal and the CG font */
869 font_info->synthItal = synthItal;
871 ATSFontRef atsFont = ATSFontFindFromPostScriptName
872 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
874 if (atsFont == kATSFontRefUnspecified)
876 /* see if we can get it by dropping italic (then synthesizing) */
877 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
878 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
879 fontName], kATSOptionFlagsDefault);
880 if (atsFont != kATSFontRefUnspecified)
881 font_info->synthItal = YES;
884 /* last resort fallback */
885 atsFont = ATSFontFindFromPostScriptName
886 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
889 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
893 /* set up metrics portion of font struct */
894 font->ascent = lrint([sfont ascender]);
895 font->descent = -lrint(floor(adjusted_descender));
896 font->min_width = ns_char_width(sfont, '|');
897 font->space_width = lrint (ns_char_width (sfont, ' '));
898 font->average_width = lrint (font_info->width);
899 font->max_width = lrint (font_info->max_bounds.width);
900 font->height = lrint (font_info->height);
901 font->underline_position = lrint (font_info->underpos);
902 font->underline_thickness = lrint (font_info->underwidth);
904 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
905 font->props[FONT_FULLNAME_INDEX] =
906 make_unibyte_string (font_info->name, strlen (font_info->name));
914 /* Close FONT on frame F. */
916 nsfont_close (FRAME_PTR f, struct font *font)
918 struct nsfont_info *font_info = (struct nsfont_info *)font;
921 /* FIXME: this occurs apparently due to same failure to detect same font
922 that causes need for cache in nsfont_open () */
926 for (i =0; i<0x100; i++)
928 xfree (font_info->glyphs[i]);
929 xfree (font_info->metrics[i]);
931 [font_info->nsfont release];
933 CGFontRelease (font_info->cgfont);
935 xfree (font_info->name);
940 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
941 return 1. If not, return 0. If a font must be opened to check
944 nsfont_has_char (Lisp_Object entity, int c)
950 /* Return a glyph code of FONT for character C (Unicode code point).
951 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
953 nsfont_encode_char (struct font *font, int c)
955 struct nsfont_info *font_info = (struct nsfont_info *)font;
956 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
960 return FONT_INVALID_CODE;
962 /* did we already cache this block? */
963 if (!font_info->glyphs[high])
964 ns_uni_to_glyphs (font_info, high);
966 g = font_info->glyphs[high][low];
967 return g == 0xFFFF ? FONT_INVALID_CODE : g;
971 /* Perform the size computation of glyphs of FONT and fill in members
972 of METRICS. The glyphs are specified by their glyph codes in
973 CODE (length NGLYPHS). */
975 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
976 struct font_metrics *metrics)
978 struct nsfont_info *font_info = (struct nsfont_info *)font;
979 struct font_metrics *pcm;
980 unsigned char high, low;
984 memset (metrics, 0, sizeof (struct font_metrics));
986 for (i =0; i<nglyphs; i++)
988 /* get metrics for this glyph, filling cache if need be */
989 /* TODO: get metrics for whole string from an NSLayoutManager
991 high = (code[i] & 0xFF00) >> 8;
992 low = code[i] & 0x00FF;
993 if (!font_info->metrics[high])
994 ns_glyph_metrics (font_info, high);
995 pcm = &(font_info->metrics[high][low]);
997 if (metrics->lbearing > totalWidth + pcm->lbearing)
998 metrics->lbearing = totalWidth + pcm->lbearing;
999 if (metrics->rbearing < totalWidth + pcm->rbearing)
1000 metrics->rbearing = totalWidth + pcm->rbearing;
1001 if (metrics->ascent < pcm->ascent)
1002 metrics->ascent = pcm->ascent;
1003 if (metrics->descent < pcm->descent)
1004 metrics->descent = pcm->descent;
1006 totalWidth += pcm->width;
1009 metrics->width = totalWidth;
1011 return totalWidth; /* not specified in doc, but xfont.c does it */
1015 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1016 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
1017 is nonzero, fill the background in advance. It is assured that
1018 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1020 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1021 int with_background)
1022 /* NOTE: focus and clip must be set
1023 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1025 static char cbuf[1024];
1027 #ifdef NS_IMPL_GNUSTEP
1028 static float advances[1024];
1029 float *adv = advances;
1031 static CGSize advances[1024];
1032 CGSize *adv = advances;
1036 struct nsfont_info *font = ns_tmp_font;
1037 NSColor *col, *bgCol;
1038 unsigned short *t = s->char2b;
1040 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1041 int end = isComposite ? s->cmp_to : s->nchars;
1043 /* Select face based on input flags */
1044 switch (ns_tmp_flags)
1046 case NS_DUMPGLYPH_CURSOR:
1049 case NS_DUMPGLYPH_MOUSEFACE:
1050 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1052 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1059 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1060 r.origin.x += abs (s->face->box_line_width);
1063 r.size.height = FONT_HEIGHT (font);
1065 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1066 NS to render the string, it will come out differently from the individual
1067 character widths added up because of layout processing. */
1070 int cwidth, twidth = 0;
1072 /* FIXME: composition: no vertical displacement is considered. */
1073 t += s->cmp_from; /* advance into composition */
1074 for (i = s->cmp_from; i < end; i++, t++)
1076 hi = (*t & 0xFF00) >> 8;
1080 if (!s->first_glyph->u.cmp.automatic)
1081 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1084 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1085 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1086 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1087 cwidth = LGLYPH_WIDTH (glyph);
1090 cwidth = LGLYPH_WADJUST (glyph);
1091 #ifdef NS_IMPL_GNUSTEP
1092 *(adv-1) += LGLYPH_XOFF (glyph);
1094 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1101 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1102 ns_glyph_metrics (font, hi);
1103 cwidth = font->metrics[hi][lo].width;
1106 #ifdef NS_IMPL_GNUSTEP
1108 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1110 (*adv++).width = cwidth;
1113 len = adv - advances;
1114 r.size.width = twidth;
1118 /* fill background if requested */
1119 if (with_background && !isComposite)
1122 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1123 int mbox_line_width = max (s->face->box_line_width, 0);
1125 if (s->row->full_width_p)
1127 if (br.origin.x <= fibw + 1 + mbox_line_width)
1129 br.size.width += br.origin.x - mbox_line_width;
1130 br.origin.x = mbox_line_width;
1132 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1134 br.size.width += fibw;
1136 if (s->face->box == FACE_NO_BOX)
1138 /* expand unboxed top row over internal border */
1139 if (br.origin.y <= fibw + 1 + mbox_line_width)
1141 br.size.height += br.origin.y;
1147 int correction = abs (s->face->box_line_width)+1;
1148 br.origin.y += correction;
1149 br.size.height -= 2*correction;
1150 br.origin.x += correction;
1151 br.size.width -= 2*correction;
1154 if (!s->face->stipple)
1155 [(NS_FACE_BACKGROUND (face) != 0
1156 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1157 : FRAME_BACKGROUND_COLOR (s->f)) set];
1160 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1161 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1167 /* set up for character rendering */
1168 r.origin.y += font->voffset + (s->height - font->height)/2;
1170 col = (NS_FACE_FOREGROUND (face) != 0
1171 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1172 : FRAME_FOREGROUND_COLOR (s->f));
1173 /* FIXME: find another way to pass this */
1174 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1175 : (NS_FACE_BACKGROUND (face) != 0
1176 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1177 : FRAME_BACKGROUND_COLOR (s->f)));
1179 /* render under GNUstep using DPS */
1180 #ifdef NS_IMPL_GNUSTEP
1182 NSGraphicsContext *context = GSCurrentContext ();
1187 /* do erase if "foreground" mode */
1191 DPSmoveto (context, r.origin.x, r.origin.y);
1192 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1193 DPSxshow (context, cbuf, advances, len);
1194 DPSstroke (context);
1196 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1200 if (face->underline_p)
1202 if (face->underline_color != 0)
1203 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1206 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1207 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1208 if (face->underline_color != 0)
1214 /* draw with DPSxshow () */
1215 DPSmoveto (context, r.origin.x, r.origin.y);
1216 DPSxshow (context, cbuf, advances, len);
1217 DPSstroke (context);
1219 DPSgrestore (context);
1222 #else /* NS_IMPL_COCOA */
1224 CGContextRef gcontext =
1225 [[NSGraphicsContext currentContext] graphicsPort];
1226 static CGAffineTransform fliptf;
1227 static BOOL firstTime = YES;
1232 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1235 CGContextSaveGState (gcontext);
1237 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1239 CGContextSetFont (gcontext, font->cgfont);
1240 CGContextSetFontSize (gcontext, font->size);
1241 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1242 CGContextSetShouldAntialias (gcontext, 0);
1244 CGContextSetShouldAntialias (gcontext, 1);
1246 CGContextSetTextMatrix (gcontext, fliptf);
1250 /* foreground drawing; erase first to avoid overstrike */
1252 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1253 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1254 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1255 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1258 if (face->underline_p)
1260 if (face->underline_color != 0)
1261 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1264 CGContextBeginPath (gcontext);
1265 CGContextMoveToPoint (gcontext,
1266 r.origin.x, r.origin.y + font->underpos);
1267 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1268 r.origin.y + font->underpos);
1269 CGContextStrokePath (gcontext);
1270 if (face->underline_color != 0)
1276 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1277 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1280 if (face->overstrike)
1282 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1283 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1287 CGContextRestoreGState (gcontext);
1289 #endif /* NS_IMPL_COCOA */
1295 /* ==========================================================================
1297 Font glyph and metrics caching functions
1299 ========================================================================== */
1301 /* Find and cache corresponding glyph codes for unicode values in given
1302 hi-byte block of 256. */
1304 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1306 #ifdef NS_IMPL_COCOA
1307 static EmacsGlyphStorage *glyphStorage;
1308 static char firstTime = 1;
1310 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1311 unsigned int i, g, idx;
1312 unsigned short *glyphs;
1315 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1320 #ifdef NS_IMPL_COCOA
1324 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1328 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1329 if (!unichars || !(font_info->glyphs[block]))
1332 /* create a string containing all unicode characters in this block */
1333 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1334 if (idx < 0xD800 || idx > 0xDFFF)
1337 unichars[i] = 0xFEFF;
1338 unichars[0x100] = 0;
1341 #ifdef NS_IMPL_COCOA
1342 NSString *allChars = [[NSString alloc]
1343 initWithCharactersNoCopy: unichars
1346 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1347 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1348 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1349 NSUInteger gInd =0, cInd =0;
1351 [glyphStorage setString: allChars font: font_info->nsfont];
1352 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1353 desiredNumberOfCharacters: glyphStorage->maxChar
1354 glyphIndex: &gInd characterIndex: &cInd];
1356 glyphs = font_info->glyphs[block];
1357 for (i =0; i<0x100; i++, glyphs++)
1359 #ifdef NS_IMPL_GNUSTEP
1362 g = glyphStorage->cglyphs[i];
1363 /* TODO: is this a good check? maybe need to use coveredChars.. */
1365 g = 0xFFFF; /* hopefully unused... */
1370 #ifdef NS_IMPL_COCOA
1380 /* Determine and cache metrics for corresponding glyph codes in given
1381 hi-byte block of 256. */
1383 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1386 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1388 struct font_metrics *metrics;
1391 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1394 #ifdef NS_IMPL_GNUSTEP
1395 /* not implemented yet (as of startup 0.18), so punt */
1397 numGlyphs = 0x10000;
1401 sfont = [font_info->nsfont screenFont];
1403 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1404 memset (font_info->metrics[block], 0, 0x100 * sizeof (struct font_metrics));
1405 if (!(font_info->metrics[block]))
1408 metrics = font_info->metrics[block];
1409 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1412 NSRect r = [sfont boundingRectForGlyph: g];
1414 w = max ([sfont advancementForGlyph: g].width, 2.0);
1415 metrics->width = lrint (w);
1418 rb = r.size.width - w;
1420 metrics->lbearing = round (lb);
1421 if (font_info->ital)
1422 rb += 0.22 * font_info->height;
1423 metrics->rbearing = lrint (w + rb);
1425 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1426 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1427 metrics->ascent = r.size.height - metrics->descent;
1428 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1434 #ifdef NS_IMPL_COCOA
1435 /* helper for font glyph setup */
1436 @implementation EmacsGlyphStorage
1440 return [self initWithCapacity: 1024];
1443 - initWithCapacity: (unsigned long) c
1445 self = [super init];
1448 dict = [NSMutableDictionary new];
1449 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1462 - (void) setString: (NSString *)str font: (NSFont *)font
1464 [dict setObject: font forKey: NSFontAttributeName];
1465 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1466 maxChar = [str length];
1470 /* NSGlyphStorage protocol */
1471 - (NSUInteger)layoutOptions
1476 - (NSAttributedString *)attributedString
1481 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1482 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1483 characterIndex: (NSUInteger)charIndex
1485 len = glyphIndex+length;
1486 for (i =glyphIndex; i<len; i++)
1487 cglyphs[i] = glyphs[i-glyphIndex];
1492 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1493 forGlyphAtIndex: (NSUInteger)glyphIndex
1499 #endif /* NS_IMPL_COCOA */
1504 ns_dump_glyphstring (struct glyph_string *s)
1508 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1509 "overlap = %d, bg_filled = %d:",
1510 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1511 s->row->overlapping_p, s->background_filled_p);
1512 for (i =0; i<s->nchars; i++)
1513 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1514 fprintf (stderr, "\n");
1519 syms_of_nsfont (void)
1521 nsfont_driver.type = Qns;
1522 register_font_driver (&nsfont_driver, NULL);
1523 DEFSYM (Qapple, "apple");
1524 DEFSYM (Qroman, "roman");
1525 DEFSYM (Qmedium, "medium");
1526 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1527 doc: /* Internal use: maps font registry to unicode script. */);