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 #define NSFONT_TRACE 0
42 extern Lisp_Object Qns;
43 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
44 static Lisp_Object Qapple, Qroman, Qmedium;
45 extern Lisp_Object Qappend;
46 extern int ns_antialias_text, ns_use_qd_smoothing;
47 extern float ns_antialias_threshold;
48 extern int ns_tmp_flags;
49 extern struct nsfont_info *ns_tmp_font;
51 /* font glyph and metrics caching functions, implemented at end */
52 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
54 static void ns_glyph_metrics (struct nsfont_info *font_info,
58 /* ==========================================================================
62 ========================================================================== */
65 /* Replace spaces w/another character so emacs core font parsing routines
68 ns_escape_name (char *name)
70 int i =0, len =strlen (name);
77 /* Reconstruct spaces in a font family name passed through emacs. */
79 ns_unescape_name (char *name)
81 int i =0, len =strlen (name);
88 /* Extract family name from a font spec. */
90 ns_get_family (Lisp_Object font_spec)
92 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
97 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
99 ns_unescape_name (tmp);
100 /* For names hard-coded into emacs, like 'helvetica' for splash. */
101 tmp[0] = toupper (tmp[0]);
102 family = [NSString stringWithUTF8String: tmp];
109 /* Return NSNumber or nil if attr is not set. */
111 *ns_attribute_value (NSFontDescriptor *fdesc, NSString *trait)
113 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
114 NSNumber *val = [tdict objectForKey: trait];
119 /* Return 0 if attr not set, else value (which might also be 0). */
121 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
123 NSNumber *val = ns_attribute_value (fdesc, trait);
124 return val == nil ? 0.0 : [val floatValue];
128 /* Return whether font has attribute set to non-standard value. */
130 ns_has_attribute (NSFontDescriptor *fdesc, NSString *trait)
132 float v = ns_attribute_fvalue (fdesc, trait);
133 return v < -0.25 || v > 0.25;
137 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
138 to NSFont descriptor. Information under extra only needed for matching. */
139 #define STYLE_REF 100
140 static NSFontDescriptor
141 *ns_spec_to_descriptor(Lisp_Object font_spec)
143 NSFontDescriptor *fdesc;
144 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
145 NSMutableDictionary *tdict = [NSMutableDictionary new];
146 NSString *family = ns_get_family (font_spec);
149 /* add each attr in font_spec to fdAttrs.. */
150 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
151 if (n != -1 && n != STYLE_REF)
152 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
153 forKey: NSFontWeightTrait];
154 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
155 if (n != -1 && n != STYLE_REF)
156 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
157 forKey: NSFontSlantTrait];
158 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
159 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
160 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
161 forKey: NSFontWidthTrait];
162 if ([tdict count] > 0)
163 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
165 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
167 fdesc = [fdesc fontDescriptorWithFamily: family];
172 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
174 ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
176 Lisp_Object font_entity = font_make_entity ();
177 /* NSString *psName = [desc postscriptName]; */
178 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
179 char *escapedFamily = strdup ([family UTF8String]);
180 unsigned int traits = [desc symbolicTraits];
182 ns_escape_name (escapedFamily);
184 ASET (font_entity, FONT_TYPE_INDEX, Qns);
185 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
186 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
187 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
188 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
190 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
191 traits & NSFontBoldTrait ? Qbold : Qmedium);
192 /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
193 make_number (100 + 100
194 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
195 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
196 traits & NSFontItalicTrait ? Qitalic : Qnormal);
197 /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
198 make_number (100 + 100
199 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
200 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
201 traits & NSFontCondensedTrait ? Qcondensed :
202 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
203 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
204 make_number (100 + 100
205 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
207 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
208 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
209 ASET (font_entity, FONT_SPACING_INDEX,
210 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
211 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
213 ASET (font_entity, FONT_EXTRA_INDEX, extra);
214 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
218 fprintf (stderr, "created font_entity:\n ");
219 debug_print (font_entity);
222 free (escapedFamily);
227 /* Default font entity. */
229 ns_fallback_entity ()
231 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
232 fontDescriptor], Qnil, NULL);
236 /* Utility: get width of a char c in screen font sfont */
238 ns_char_width (NSFont *sfont, int c)
241 NSString *cstr = [NSString stringWithFormat: @"%c", c];
243 NSGlyph glyph = [sfont glyphWithName: cstr];
246 float w = [sfont advancementForGlyph: glyph].width;
251 w = [sfont widthOfString: cstr];
256 /* Return whether set1 covers set2 to a reasonable extent given by pct.
257 We check, out of each 16 unicode char range containing chars in set2,
258 whether at least one character is present in set1.
259 This must be true for pct of the pairs to consider it covering. */
261 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
263 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
264 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
265 int i, off = 0, tot = 0;
267 for (i=0; i<4096; i++, bytes1++, bytes2++)
271 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
274 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
275 return (float)off / tot < 1.0 - pct;
279 /* Convert :lang property to a script. Use of :lang property by font backend
280 seems to be limited for now (2009/05) to ja, zh, and ko. */
282 *ns_lang_to_script (Lisp_Object lang)
284 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
286 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
287 have more characters. */
288 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
290 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
297 /* Convert OTF 4-letter script code to emacs script name. (Why can't
298 everyone just use some standard unicode names for these?) */
300 *ns_otf_to_script (Lisp_Object otf)
302 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
303 return CONSP (script)
304 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
309 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec
310 for something that can be mapped to a unicode script. Empty string returned
311 if no script spec found.
312 TODO: Eventually registry / encoding should be checked and mapped, but for
313 now the font backend will try script/lang/otf if registry fails, so it is
316 *ns_get_req_script (Lisp_Object font_spec)
318 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
320 for ( ; CONSP (extra); extra = XCDR (extra))
322 Lisp_Object tmp = XCAR (extra);
325 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
326 if (EQ (key, QCscript) && SYMBOLP (val))
327 return [NSString stringWithUTF8String:
328 SDATA (SYMBOL_NAME (val))];
329 if (EQ (key, QClang) && SYMBOLP (val))
330 return ns_lang_to_script (val);
331 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
332 return ns_otf_to_script (val);
339 /* This small function is static in fontset.c. If it can be made public for
340 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
342 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
344 if (EQ (XCAR (arg), val))
347 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
349 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
354 /* Use the unicode range information in Vchar_script_table to convert a script
355 name into an NSCharacterSet. */
356 static NSCharacterSet
357 *ns_script_to_charset (NSString *scriptName)
359 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
360 Lisp_Object script = intern ([scriptName UTF8String]);
361 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
363 if (! NILP (Fmemq (script, script_list)))
365 Lisp_Object ranges, range_list;
367 ranges = Fcons (script, Qnil);
368 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
370 range_list = Fnreverse (XCDR (ranges));
371 if (! NILP (range_list))
373 for (; CONSP (range_list); range_list = XCDR (range_list))
375 int start = XINT (XCAR (XCAR (range_list)));
376 int end = XINT (XCDR (XCAR (range_list)));
378 debug_print (XCAR (range_list));
380 [charset addCharactersInRange:
381 NSMakeRange (start, end-start)];
389 /* Return an array of font families containing characters for the given
390 script, for the given coverage criterion, including at least LastResort.
391 Results are cached by script for faster access.
392 If none are found, we reduce the percentage and try again, until 5%.
393 This provides a font with at least some characters if such can be found.
394 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
395 (b) need approximate match as fonts covering full unicode ranges are rare. */
397 *ns_get_covering_families (NSString *script, float pct)
399 static NSMutableDictionary *scriptToFamilies = nil;
400 NSMutableSet *families;
403 NSLog(@"Request covering families for script: '%@'", script);
405 if (scriptToFamilies == nil)
406 scriptToFamilies = [NSMutableDictionary dictionaryWithCapacity: 30];
408 if ((families = [scriptToFamilies objectForKey: script]) == nil)
410 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
411 NSArray *allFamilies = [fontMgr availableFontFamilies];
413 if ([script length] == 0)
414 families = [NSMutableSet setWithArray: allFamilies];
417 NSCharacterSet *charset = ns_script_to_charset (script);
419 families = [NSMutableSet setWithCapacity: 10];
422 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
423 while (family = [allFamiliesEnum nextObject])
425 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
426 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
427 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
429 fset = [NSCharacterSet characterSetWithRange:
430 NSMakeRange (0, 127)];
431 if (ns_charset_covers(fset, charset, pct))
432 [families addObject: family];
435 if ([families count] > 0 || pct < 0.05)
440 if ([families count] == 0)
441 [families addObject: @"LastResort"];
443 [scriptToFamilies setObject: families forKey: script];
447 NSLog(@" returning %d families", [families count]);
452 /* Implementation for list() and match(). List() can return nil, match()
453 must return something. Strategy is to drop family name from attribute
454 matching set for match. */
456 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
458 Lisp_Object tem, list = Qnil;
459 NSFontDescriptor *fdesc, *desc;
461 NSArray *matchingDescs;
469 fprintf (stderr, "nsfont: %s for fontspec:\n ",
470 (isMatch ? "match" : "list"));
471 debug_print (font_spec);
474 /* If has non-unicode registry, give up. */
475 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
476 if (! NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
477 return isMatch ? ns_fallback_entity () : Qnil;
479 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
481 fdesc = ns_spec_to_descriptor (font_spec);
482 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
484 [fkeys removeObject: NSFontFamilyAttribute];
486 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
488 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
489 [matchingDescs count]);
491 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
493 if (![cFamilies containsObject:
494 [desc objectForKey: NSFontFamilyAttribute]])
496 list = Fcons (ns_descriptor_to_entity (desc,
497 AREF (font_spec, FONT_EXTRA_INDEX),
499 if (ns_has_attribute (desc, NSFontSlantTrait))
503 /* Add synthItal member if needed. */
504 family = [fdesc objectForKey: NSFontFamilyAttribute];
505 if (family != nil && !foundItal && XINT (Flength (list)) > 0
506 && (ns_attribute_value (fdesc, NSFontSlantTrait) == nil
507 || ns_has_attribute (fdesc, NSFontSlantTrait)))
509 NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
510 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
511 fontDescriptorWithFamily: family];
512 list = Fcons (ns_descriptor_to_entity (sDesc,
513 AREF (font_spec, FONT_EXTRA_INDEX),
518 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
525 /* ==========================================================================
527 Font driver implementation
529 ========================================================================== */
532 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
533 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
534 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
535 static Lisp_Object nsfont_list_family (Lisp_Object frame);
536 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
538 static void nsfont_close (FRAME_PTR f, struct font *font);
539 static int nsfont_has_char (Lisp_Object entity, int c);
540 static unsigned int nsfont_encode_char (struct font *font, int c);
541 static int nsfont_text_extents (struct font *font, unsigned int *code,
542 int nglyphs, struct font_metrics *metrics);
543 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
544 int with_background);
546 struct font_driver nsfont_driver =
549 1, /* case sensitive */
554 NULL, /*free_entity */
557 NULL, /* prepare_face */
558 NULL, /* done_face */
563 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
564 anchor_point, otf_capability, otf_driver,
565 start_for_frame, end_for_frame, shape */
569 /* Return a cache of font-entities on FRAME. The cache must be a
570 cons whose cdr part is the actual cache area. */
572 nsfont_get_cache (FRAME_PTR frame)
574 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
575 return (dpyinfo->name_list_element);
579 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
580 **list** of font-entities. This and match () are sole APIs that allocate
581 font-entities. Properties to be considered (2009/05/19) are:
582 regular: foundry, family, adstyle, registry
583 extended: script, lang, otf
584 "Extended" properties are not part of the vector but get stored as
585 lisp properties under FONT_EXTRA_INDEX.
587 The returned entities should have type set (to 'ns), plus the following:
588 foundry, family, adstyle, registry,
589 weight, slant, width, size (0 if scalable),
590 dpi, spacing, avgwidth (0 if scalable) */
592 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
594 return ns_findfonts (font_spec, NO);
598 /* Return a font entity most closely maching with FONT_SPEC on
599 FRAME. The closeness is determined by the font backend, thus
600 `face-font-selection-order' is ignored here.
601 Properties to be considered are same as for list(). */
603 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
605 return ns_findfonts(font_spec, YES);
609 /* List available families. The value is a list of family names
612 nsfont_list_family (Lisp_Object frame)
614 Lisp_Object list = Qnil;
615 NSEnumerator *families =
616 [[[NSFontManager sharedFontManager] availableFontFamilies]
619 while (family = [families nextObject])
620 list = Fcons (intern ([family UTF8String]), list);
621 /* FIXME: escape the name? */
624 fprintf (stderr, "nsfont: list families returning %d entries\n",
625 XINT (Flength (list)));
631 /* Open a font specified by FONT_ENTITY on frame F. If the font is
632 scalable, open it with PIXEL_SIZE. */
634 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
637 unsigned int traits = 0;
638 struct nsfont_info *font_info;
640 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
641 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
643 NSFont *nsfont, *sfont;
646 Lisp_Object font_object;
649 static NSMutableDictionary *fontCache = nil;
652 /* 2008/03/08: The same font may end up being requested for different
653 entities, due to small differences in numeric values or other issues,
654 or for different copies of the same entity. Therefore we cache to
655 avoid creating multiple struct font objects (with metrics cache, etc.)
656 for the same NSFont object. */
657 if (fontCache == nil)
658 fontCache = [[NSMutableDictionary alloc] init];
662 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
663 debug_print (font_entity);
668 /* try to get it out of frame params */
669 Lisp_Object tem = get_frame_param (f, Qfontsize);
670 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
673 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
674 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
676 family = ns_get_family (font_entity);
677 if (ns_has_attribute (fontDesc, NSFontWeightTrait))
678 traits |= NSBoldFontMask;
679 if (ns_has_attribute (fontDesc, NSFontSlantTrait))
680 traits |= NSItalicFontMask;
682 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
683 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
684 nsfont = [fontMgr fontWithFamily: family
685 traits: traits weight: fixLeopardBug
687 /* if didn't find, try synthetic italic */
688 if (nsfont == nil && synthItal)
690 nsfont = [fontMgr fontWithFamily: family
691 traits: traits & ~NSItalicFontMask
692 weight: fixLeopardBug size: pixel_size];
695 /* LastResort not really a family */
696 if (nsfont == nil && [@"LastResort" isEqualToString: family])
697 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
702 message_with_string ("*** Warning: font in family '%s' not found",
703 build_string ([family UTF8String]), 1);
704 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
708 NSLog (@"%@\n", nsfont);
710 /* Check the cache */
711 cached = [fontCache objectForKey: nsfont];
712 if (cached != nil && !synthItal)
715 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
716 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
717 XHASH (font_object) = [cached unsignedLongValue];
722 font_object = font_make_object (VECSIZE (struct nsfont_info),
723 font_entity, pixel_size);
725 [fontCache setObject: [NSNumber numberWithUnsignedLong:
726 (unsigned long) XHASH (font_object)]
730 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
731 font = (struct font *) font_info;
733 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
735 font_info->glyphs = (unsigned short **)
736 xmalloc (0x100 * sizeof (unsigned short *));
737 font_info->metrics = (struct font_metrics **)
738 xmalloc (0x100 * sizeof (struct font_metrics *));
739 if (!font_info->glyphs || !font_info->metrics)
741 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
742 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
747 sfont = [nsfont screenFont];
751 /* non-metric backend font struct fields */
752 font = (struct font *) font_info;
753 font->pixel_size = [sfont pointSize];
754 font->driver = &nsfont_driver;
755 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
756 font->encoding_charset = -1;
757 font->repertory_charset = -1;
758 font->default_ascent = 0;
759 font->vertical_centering = 0;
760 font->baseline_offset = 0;
761 font->relative_compose = 0;
762 font->font_encoder = NULL;
764 font->props[FONT_FORMAT_INDEX] = Qns;
765 font->props[FONT_FILE_INDEX] = Qnil;
768 double expand, hshrink;
769 float full_height, min_height, hd;
770 const char *fontName = [[nsfont fontName] UTF8String];
771 int len = strlen (fontName);
773 #ifdef NS_IMPL_GNUSTEP
774 font_info->nsfont = sfont;
776 font_info->nsfont = nsfont;
778 [font_info->nsfont retain];
780 /* set up ns_font (defined in nsgui.h) */
781 font_info->name = (char *)xmalloc (strlen (fontName) + 1);
782 bcopy (fontName, font_info->name, strlen (fontName) + 1);
783 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
785 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
787 /* Metrics etc.; some fonts return an unusually large max advance, so we
788 only use it for fonts that have wide characters. */
789 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
790 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
792 brect = [sfont boundingRectForFont];
793 full_height = brect.size.height;
794 min_height = [sfont ascender] - [sfont descender];
795 hd = full_height - min_height;
797 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
801 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
802 font_info->underwidth = [sfont underlineThickness];
803 font_info->size = font->pixel_size;
804 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
807 font_info->max_bounds.ascent =
808 lrint (hshrink * [sfont ascender] + expand * hd/2);
809 font_info->max_bounds.descent =
810 -lrint (hshrink* [sfont descender] - expand*hd/2);
812 font_info->max_bounds.ascent + font_info->max_bounds.descent;
813 font_info->max_bounds.width = lrint (font_info->width);
814 font_info->max_bounds.lbearing = lrint (brect.origin.x);
815 font_info->max_bounds.rbearing =
816 lrint (brect.size.width - font_info->width);
819 /* set up synthItal and the CG font */
820 font_info->synthItal = synthItal;
822 ATSFontRef atsFont = ATSFontFindFromPostScriptName
823 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
825 if (atsFont == kATSFontRefUnspecified)
827 /* see if we can get it by dropping italic (then synthesizing) */
828 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
829 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
830 fontName], kATSOptionFlagsDefault);
831 if (atsFont != kATSFontRefUnspecified)
832 font_info->synthItal = YES;
835 /* last resort fallback */
836 atsFont = ATSFontFindFromPostScriptName
837 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
840 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
844 /* set up metrics portion of font struct */
845 font->ascent = [sfont ascender];
846 font->descent = -[sfont descender];
847 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
848 font->space_width = lrint (ns_char_width (sfont, ' '));
849 font->average_width = lrint (font_info->width);
850 font->max_width = lrint (font_info->max_bounds.width);
851 font->height = lrint (font_info->height);
852 font->underline_position = lrint (font_info->underpos);
853 font->underline_thickness = lrint (font_info->underwidth);
855 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
856 font->props[FONT_FULLNAME_INDEX] =
857 make_unibyte_string (font_info->name, strlen (font_info->name));
865 /* Close FONT on frame F. */
867 nsfont_close (FRAME_PTR f, struct font *font)
869 struct nsfont_info *font_info = (struct nsfont_info *)font;
872 /* FIXME: this occurs apparently due to same failure to detect same font
873 that causes need for cache in nsfont_open () */
877 for (i =0; i<0x100; i++)
879 if (font_info->glyphs[i])
880 xfree (font_info->glyphs[i]);
881 if (font_info->metrics[i])
882 xfree (font_info->metrics[i]);
884 [font_info->nsfont release];
886 CGFontRelease (font_info->cgfont);
888 xfree (font_info->name);
893 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
894 return 1. If not, return 0. If a font must be opened to check
897 nsfont_has_char (Lisp_Object entity, int c)
903 /* Return a glyph code of FONT for character C (Unicode code point).
904 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
906 nsfont_encode_char (struct font *font, int c)
908 struct nsfont_info *font_info = (struct nsfont_info *)font;
909 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
913 return FONT_INVALID_CODE;
915 /* did we already cache this block? */
916 if (!font_info->glyphs[high])
917 ns_uni_to_glyphs (font_info, high);
919 g = font_info->glyphs[high][low];
920 return g == 0xFFFF ? FONT_INVALID_CODE : g;
924 /* Perform the size computation of glyphs of FONT and fill in members
925 of METRICS. The glyphs are specified by their glyph codes in
926 CODE (length NGLYPHS). */
928 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
929 struct font_metrics *metrics)
931 struct nsfont_info *font_info = (struct nsfont_info *)font;
932 struct font_metrics *pcm;
933 unsigned char high, low;
937 bzero (metrics, sizeof (struct font_metrics));
939 for (i =0; i<nglyphs; i++)
941 /* get metrics for this glyph, filling cache if need be */
942 /* TODO: get metrics for whole string from an NSLayoutManager
944 high = (code[i] & 0xFF00) >> 8;
945 low = code[i] & 0x00FF;
946 if (!font_info->metrics[high])
947 ns_glyph_metrics (font_info, high);
948 pcm = &(font_info->metrics[high][low]);
950 if (metrics->lbearing > totalWidth + pcm->lbearing)
951 metrics->lbearing = totalWidth + pcm->lbearing;
952 if (metrics->rbearing < totalWidth + pcm->rbearing)
953 metrics->rbearing = totalWidth + pcm->rbearing;
954 if (metrics->ascent < pcm->ascent)
955 metrics->ascent = pcm->ascent;
956 if (metrics->descent < pcm->descent)
957 metrics->descent = pcm->descent;
959 totalWidth += pcm->width;
962 metrics->width = totalWidth;
964 return totalWidth; /* not specified in doc, but xfont.c does it */
968 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
969 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
970 is nonzero, fill the background in advance. It is assured that
971 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
973 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
975 /* NOTE: focus and clip must be set
976 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
978 static char cbuf[1024];
980 #ifdef NS_IMPL_GNUSTEP
981 static float advances[1024];
982 float *adv = advances;
984 static CGSize advances[1024];
985 CGSize *adv = advances;
989 struct nsfont_info *font = ns_tmp_font;
990 NSColor *col, *bgCol;
991 unsigned short *t = s->char2b;
993 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
994 int end = isComposite ? s->cmp_to : s->nchars;
996 /* Select face based on input flags */
997 switch (ns_tmp_flags)
999 case NS_DUMPGLYPH_CURSOR:
1002 case NS_DUMPGLYPH_MOUSEFACE:
1003 face = FACE_FROM_ID (s->f,
1004 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1006 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1013 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1014 r.origin.x += abs (s->face->box_line_width);
1017 r.size.height = FONT_HEIGHT (font);
1019 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1020 NS to render the string, it will come out differently from the individual
1021 character widths added up because of layout processing. */
1024 int cwidth, twidth = 0;
1026 /* FIXME: composition: no vertical displacement is considered. */
1027 t += s->cmp_from; /* advance into composition */
1028 for (i = s->cmp_from; i < end; i++, t++)
1030 hi = (*t & 0xFF00) >> 8;
1034 if (!s->first_glyph->u.cmp.automatic)
1035 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1038 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1039 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1040 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1041 cwidth = LGLYPH_WIDTH (glyph);
1044 cwidth = LGLYPH_WADJUST (glyph);
1045 #ifdef NS_IMPL_GNUSTEP
1046 *(adv-1) += LGLYPH_XOFF (glyph);
1048 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1055 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1056 ns_glyph_metrics (font, hi);
1057 cwidth = font->metrics[hi][lo].width;
1060 #ifdef NS_IMPL_GNUSTEP
1062 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1064 (*adv++).width = cwidth;
1067 len = adv - advances;
1068 r.size.width = twidth;
1072 /* fill background if requested */
1073 if (with_background && !isComposite)
1076 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1077 int mbox_line_width = max (s->face->box_line_width, 0);
1079 if (s->row->full_width_p)
1081 if (br.origin.x <= fibw + 1 + mbox_line_width)
1083 br.size.width += br.origin.x - mbox_line_width;
1084 br.origin.x = mbox_line_width;
1086 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1088 br.size.width += fibw;
1090 if (s->face->box == FACE_NO_BOX)
1092 /* expand unboxed top row over internal border */
1093 if (br.origin.y <= fibw + 1 + mbox_line_width)
1095 br.size.height += br.origin.y;
1101 int correction = abs (s->face->box_line_width)+1;
1102 br.origin.y += correction;
1103 br.size.height -= 2*correction;
1104 br.origin.x += correction;
1105 br.size.width -= 2*correction;
1108 if (!s->face->stipple)
1109 [(NS_FACE_BACKGROUND (face) != 0
1110 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1111 : FRAME_BACKGROUND_COLOR (s->f)) set];
1114 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1115 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1121 /* set up for character rendering */
1122 r.origin.y += font->voffset + (s->height - font->height)/2;
1124 col = (NS_FACE_FOREGROUND (face) != 0
1125 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1126 : FRAME_FOREGROUND_COLOR (s->f));
1127 /* FIXME: find another way to pass this */
1128 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1129 : (NS_FACE_BACKGROUND (face) != 0
1130 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1131 : FRAME_BACKGROUND_COLOR (s->f)));
1133 /* render under GNUstep using DPS */
1134 #ifdef NS_IMPL_GNUSTEP
1136 NSGraphicsContext *context = GSCurrentContext ();
1141 /* do erase if "foreground" mode */
1145 DPSmoveto (context, r.origin.x, r.origin.y);
1146 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1147 DPSxshow (context, cbuf, advances, len);
1148 DPSstroke (context);
1150 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1154 if (face->underline_p)
1156 if (face->underline_color != 0)
1157 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1160 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1161 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1162 if (face->underline_color != 0)
1168 /* draw with DPSxshow () */
1169 DPSmoveto (context, r.origin.x, r.origin.y);
1170 DPSxshow (context, cbuf, advances, len);
1171 DPSstroke (context);
1173 DPSgrestore (context);
1177 #else /* NS_IMPL_COCOA */
1179 CGContextRef gcontext =
1180 [[NSGraphicsContext currentContext] graphicsPort];
1181 static CGAffineTransform fliptf;
1182 static BOOL firstTime = YES;
1187 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1190 CGContextSaveGState (gcontext);
1192 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1194 CGContextSetFont (gcontext, font->cgfont);
1195 CGContextSetFontSize (gcontext, font->size);
1196 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1197 CGContextSetShouldAntialias (gcontext, 0);
1199 CGContextSetShouldAntialias (gcontext, 1);
1200 if (EQ (ns_use_qd_smoothing, Qt))
1201 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1203 CGContextSetTextMatrix (gcontext, fliptf);
1207 /* foreground drawing; erase first to avoid overstrike */
1209 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1210 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1211 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1212 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1215 if (face->underline_p)
1217 if (face->underline_color != 0)
1218 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1221 CGContextBeginPath (gcontext);
1222 CGContextMoveToPoint (gcontext,
1223 r.origin.x, r.origin.y + font->underpos);
1224 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1225 r.origin.y + font->underpos);
1226 CGContextStrokePath (gcontext);
1227 if (face->underline_color != 0)
1233 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1234 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1237 if (face->overstrike)
1239 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1240 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1244 CGContextRestoreGState (gcontext);
1247 #endif /* NS_IMPL_COCOA */
1253 /* ==========================================================================
1255 Font glyph and metrics caching functions
1257 ========================================================================== */
1259 /* Find and cache corresponding glyph codes for unicode values in given
1260 hi-byte block of 256. */
1262 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1264 #ifdef NS_IMPL_COCOA
1265 static EmacsGlyphStorage *glyphStorage;
1266 static char firstTime = 1;
1268 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1269 unsigned int i, g, idx;
1270 unsigned short *glyphs;
1273 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1278 #ifdef NS_IMPL_COCOA
1282 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1286 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1287 if (!unichars || !(font_info->glyphs[block]))
1290 /* create a string containing all unicode characters in this block */
1291 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1292 if (idx < 0xD800 || idx > 0xDFFF)
1295 unichars[i] = 0xFEFF;
1296 unichars[0x100] = 0;
1299 #ifdef NS_IMPL_COCOA
1300 NSString *allChars = [[NSString alloc]
1301 initWithCharactersNoCopy: unichars
1304 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1305 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1306 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1307 unsigned int gInd =0, cInd =0;
1309 [glyphStorage setString: allChars font: font_info->nsfont];
1310 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1311 desiredNumberOfCharacters: glyphStorage->maxChar
1312 glyphIndex: &gInd characterIndex: &cInd];
1314 glyphs = font_info->glyphs[block];
1315 for (i =0; i<0x100; i++, glyphs++)
1317 #ifdef NS_IMPL_GNUSTEP
1320 g = glyphStorage->cglyphs[i];
1321 /* TODO: is this a good check? maybe need to use coveredChars.. */
1323 g = 0xFFFF; /* hopefully unused... */
1328 #ifdef NS_IMPL_COCOA
1338 /* Determine and cache metrics for corresponding glyph codes in given
1339 hi-byte block of 256. */
1341 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1344 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1346 struct font_metrics *metrics;
1349 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1352 #ifdef NS_IMPL_GNUSTEP
1353 /* not implemented yet (as of startup 0.18), so punt */
1355 numGlyphs = 0x10000;
1359 sfont = [font_info->nsfont screenFont];
1361 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1362 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1363 if (!(font_info->metrics[block]))
1366 metrics = font_info->metrics[block];
1367 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1370 NSRect r = [sfont boundingRectForGlyph: g];
1372 #ifdef NS_IMPL_GNUSTEP
1375 NSString *s = [NSString stringWithFormat: @"%c", g];
1376 w = [sfont widthOfString: s];
1379 w = [sfont advancementForGlyph: g].width;
1382 metrics->width = lrint (w);
1385 rb = r.size.width - w;
1387 metrics->lbearing = round (lb);
1388 if (font_info->ital)
1389 rb += 0.22 * font_info->height;
1390 metrics->rbearing = lrint (w + rb);
1392 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1393 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1394 metrics->ascent = r.size.height - metrics->descent;
1395 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1401 #ifdef NS_IMPL_COCOA
1402 /* helper for font glyph setup */
1403 @implementation EmacsGlyphStorage
1407 return [self initWithCapacity: 1024];
1410 - initWithCapacity: (unsigned long) c
1412 self = [super init];
1415 dict = [NSMutableDictionary new];
1416 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1429 - (void) setString: (NSString *)str font: (NSFont *)font
1431 [dict setObject: font forKey: NSFontAttributeName];
1432 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1433 maxChar = [str length];
1437 /* NSGlyphStorage protocol */
1438 - (unsigned int)layoutOptions
1443 - (NSAttributedString *)attributedString
1448 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1449 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1450 characterIndex: (unsigned int)charIndex
1452 len = glyphIndex+length;
1453 for (i =glyphIndex; i<len; i++)
1454 cglyphs[i] = glyphs[i-glyphIndex];
1459 - (void)setIntAttribute: (int)attributeTag value: (int)val
1460 forGlyphAtIndex: (unsigned)glyphIndex
1466 #endif /* NS_IMPL_COCOA */
1471 ns_dump_glyphstring (struct glyph_string *s)
1475 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1476 "overlap = %d, bg_filled = %d:",
1477 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1478 s->row->overlapping_p, s->background_filled_p);
1479 for (i =0; i<s->nchars; i++)
1480 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1481 fprintf (stderr, "\n");
1488 nsfont_driver.type = Qns;
1489 register_font_driver (&nsfont_driver, NULL);
1490 DEFSYM (Qapple, "apple");
1491 DEFSYM (Qroman, "roman");
1492 DEFSYM (Qmedium, "medium");
1495 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae