* etc/NEWS, doc/lispref/tips.texi (Coding Conventions): Mention
[emacs.git] / src / nsfont.m
blobebee363651f16d751d18c36c96e4fc447ec9d248
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006-2013 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. */
25 #include <config.h>
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
31 #include "charset.h"
32 #include "frame.h"
33 #include "window.h"
34 #include "fontset.h"
35 #include "nsterm.h"
36 #include "frame.h"
37 #include "character.h"
38 #include "font.h"
39 #include "termchar.h"
41 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
42 #ifdef NS_IMPL_GNUSTEP
43 #import <AppKit/NSFontDescriptor.h>
44 #endif
46 #define NSFONT_TRACE 0
47 #define LCD_SMOOTHING_MARGIN 2
49 extern Lisp_Object Qns;
50 extern Lisp_Object Qnormal, Qbold, Qitalic;
51 static Lisp_Object Qapple, Qroman, Qmedium;
52 static Lisp_Object Qcondensed, Qexpanded;
53 extern Lisp_Object Qappend;
54 extern float ns_antialias_threshold;
55 extern int ns_tmp_flags;
56 extern struct nsfont_info *ns_tmp_font;
59 /* font glyph and metrics caching functions, implemented at end */
60 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
61                               unsigned char block);
62 static void ns_glyph_metrics (struct nsfont_info *font_info,
63                               unsigned char block);
66 /* ==========================================================================
68     Utilities
70    ========================================================================== */
73 /* Replace spaces w/another character so emacs core font parsing routines
74    aren't thrown off. */
75 static void
76 ns_escape_name (char *name)
78   for (; *name; name++)
79     if (*name == ' ')
80       *name = '_';
84 /* Reconstruct spaces in a font family name passed through emacs. */
85 static void
86 ns_unescape_name (char *name)
88   for (; *name; name++)
89     if (*name == '_')
90       *name = ' ';
94 /* Extract family name from a font spec. */
95 static NSString *
96 ns_get_family (Lisp_Object font_spec)
98   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
99   if (NILP (tem))
100       return nil;
101   else
102     {
103       char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
104       NSString *family;
105       ns_unescape_name (tmp);
106       family = [NSString stringWithUTF8String: tmp];
107       xfree (tmp);
108       return family;
109     }
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. */
117 static float
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);
136     float n;
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];
155     if (family != nil)
156       {
157         fdesc = [fdesc fontDescriptorWithFamily: family];
158       }
160     [fdAttrs release];
161     [tdict release];
162     return fdesc;
166 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
167 static Lisp_Object
168 ns_descriptor_to_entity (NSFontDescriptor *desc,
169                          Lisp_Object extra,
170                          const char *style)
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];
176     char *escapedFamily;
178     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
179     if (family == nil)
180       family = [desc objectForKey: NSFontNameAttribute];
181     if (family == nil)
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);
219     if (NSFONT_TRACE)
220       {
221         fprintf (stderr, "created font_entity:\n    ");
222         debug_print (font_entity);
223       }
225     xfree (escapedFamily);
226     return font_entity;
230 /* Default font entity. */
231 static Lisp_Object
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 */
240 static float
241 ns_char_width (NSFont *sfont, int c)
243   float w = -1.0;
244   NSString *cstr = [NSString stringWithFormat: @"%c", c];
246 #ifdef NS_IMPL_COCOA
247   NSGlyph glyph = [sfont glyphWithName: cstr];
248   if (glyph)
249     w = [sfont advancementForGlyph: glyph].width;
250 #endif
252   if (w < 0.0)
253     {
254       NSDictionary *attrsDictionary =
255         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
256       w = [cstr sizeWithAttributes: attrsDictionary].width;
257     }
259   return max (w, 1.0);
262 /* Return average width over ASCII printable characters for SFONT.  */
264 static NSString *ascii_printable;
266 static int
267 ns_ascii_average_width (NSFont *sfont)
269   float w = -1.0;
271   if (!ascii_printable)
272     {
273       char chars[96];
274       int ch;
275       for (ch = 0; ch < 95; ch++)
276         chars[ch] = ' ' + ch;
277       chars[95] = '\0';
279       ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
280     }
282 #ifdef NS_IMPL_COCOA
283   NSGlyph glyph = [sfont glyphWithName: ascii_printable];
284   if (glyph)
285     w = [sfont advancementForGlyph: glyph].width;
286 #endif
288   if (w < 0.0)
289     {
290       NSDictionary *attrsDictionary =
291         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
292       w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
293     }
295   return lrint (w / 95.0);
299 /* Return whether set1 covers set2 to a reasonable extent given by pct.
300    We check, out of each 16 Unicode char range containing chars in set2,
301    whether at least one character is present in set1.
302    This must be true for pct of the pairs to consider it covering. */
303 static BOOL
304 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
306     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
307     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
308     int i, off = 0, tot = 0;
310     /* Work around what appears to be a GNUstep bug.
311        See <http://bugs.gnu.org/11853>.  */
312     if (! (bytes1 && bytes2))
313       return NO;
315     for (i=0; i<4096; i++, bytes1++, bytes2++)
316         if (*bytes2)
317           {
318             tot++;
319             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
320                 off++;
321           }
322 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
323     return (float)off / tot < 1.0 - pct;
327 /* Convert :lang property to a script.  Use of :lang property by font backend
328    seems to be limited for now (2009/05) to ja, zh, and ko. */
329 static NSString
330 *ns_lang_to_script (Lisp_Object lang)
332     if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
333         return @"han";
334     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
335              have more characters. */
336     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
337         return @"han";
338     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
339         return @"hangul";
340     else
341         return @"";
345 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
346    everyone just use some standard Unicode names for these?) */
347 static NSString
348 *ns_otf_to_script (Lisp_Object otf)
350     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
351     return CONSP (script)
352         ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
353         : @"";
357 /* Convert a font registry, such as  */
358 static NSString
359 *ns_registry_to_script (char *reg)
361     Lisp_Object script, r, rts = Vns_reg_to_script;
362     while CONSP (rts)
363       {
364         r = XCAR (XCAR (rts));
365         if (!strncmp (SSDATA (r), reg, SBYTES (r)))
366           {
367             script = XCDR (XCAR (rts));
368             return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
369           }
370         rts = XCDR (rts);
371       }
372     return  @"";
376 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
377    plus registry regular property, for something that can be mapped to a
378    Unicode script.  Empty string returned if no script spec found. */
379 static NSString
380 *ns_get_req_script (Lisp_Object font_spec)
382     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
383     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
385     /* The extra-bundle properties have priority. */
386     for ( ; CONSP (extra); extra = XCDR (extra))
387       {
388         Lisp_Object tmp = XCAR (extra);
389         if (CONSP (tmp))
390           {
391             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
392             if (EQ (key, QCscript) && SYMBOLP (val))
393                 return [NSString stringWithUTF8String:
394                             SSDATA (SYMBOL_NAME (val))];
395             if (EQ (key, QClang) && SYMBOLP (val))
396                 return ns_lang_to_script (val);
397             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
398                 return ns_otf_to_script (val);
399           }
400       }
402     /* If we get here, check the charset portion of the registry. */
403     if (! NILP (reg))
404       {
405         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
406            (which causes box rendering if we don't treat it like iso8858-1)
407            but also for ascii (which causes unnecessary font substitution). */
408 #if 0
409         if (EQ (reg, Qiso10646_1))
410           reg = Qiso8859_1;
411 #endif
412         return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
413       }
415     return @"";
419 /* This small function is static in fontset.c.  If it can be made public for
420    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
421 static void
422 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
424     if (EQ (XCAR (arg), val))
425       {
426         if (CONSP (range))
427           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
428         else
429           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
430       }
434 /* Use the Unicode range information in Vchar_script_table to convert a script
435    name into an NSCharacterSet. */
436 static NSCharacterSet
437 *ns_script_to_charset (NSString *scriptName)
439     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
440     Lisp_Object script = intern ([scriptName UTF8String]);
441     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
443     if (! NILP (Fmemq (script, script_list)))
444       {
445         Lisp_Object ranges, range_list;
447         ranges = Fcons (script, Qnil);
448         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
449                         ranges);
450         range_list = Fnreverse (XCDR (ranges));
451         if (! NILP (range_list))
452           {
453             for (; CONSP (range_list); range_list = XCDR (range_list))
454               {
455                 int start = XINT (XCAR (XCAR (range_list)));
456                 int end = XINT (XCDR (XCAR (range_list)));
457                 if (NSFONT_TRACE)
458                     debug_print (XCAR (range_list));
459                 if (end < 0x10000)
460                     [charset addCharactersInRange:
461                         NSMakeRange (start, end-start)];
462               }
463           }
464       }
465     return charset;
469 /* Return an array of font families containing characters for the given
470    script, for the given coverage criterion, including at least LastResort.
471    Results are cached by script for faster access.
472    If none are found, we reduce the percentage and try again, until 5%.
473    This provides a font with at least some characters if such can be found.
474    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
475    (b) need approximate match as fonts covering full Unicode ranges are rare. */
476 static NSSet
477 *ns_get_covering_families (NSString *script, float pct)
479     static NSMutableDictionary *scriptToFamilies = nil;
480     NSMutableSet *families;
482     if (NSFONT_TRACE)
483         NSLog(@"Request covering families for script: '%@'", script);
485     if (scriptToFamilies == nil)
486         scriptToFamilies = [[NSMutableDictionary alloc] init];
488     if ((families = [scriptToFamilies objectForKey: script]) == nil)
489       {
490         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
491         NSArray *allFamilies = [fontMgr availableFontFamilies];
493         if ([script length] == 0)
494             families = [NSMutableSet setWithArray: allFamilies];
495         else
496           {
497             NSCharacterSet *charset = ns_script_to_charset (script);
498             NSString *family;
499             families = [NSMutableSet setWithCapacity: 10];
500             while (1)
501               {
502                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
503                 while ((family = [allFamiliesEnum nextObject]))
504                   {
505                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
506                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
507                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
508                     if (fset == nil)
509                       fset = [NSCharacterSet characterSetWithRange:
510                                                NSMakeRange (0, 127)];
511                     if (ns_charset_covers(fset, charset, pct))
512                         [families addObject: family];
513                   }
514                 pct -= 0.2;
515                 if ([families count] > 0 || pct < 0.05)
516                     break;
517               }
518             [charset release];
519           }
520 #ifdef NS_IMPL_COCOA
521         if ([families count] == 0)
522             [families addObject: @"LastResort"];
523 #endif
524         [scriptToFamilies setObject: families forKey: script];
525       }
527     if (NSFONT_TRACE)
528         NSLog(@"    returning %d families", [families count]);
529     return families;
533 /* Implementation for list() and match().  List() can return nil, match()
534 must return something.  Strategy is to drop family name from attribute
535 matching set for match. */
536 static Lisp_Object
537 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
539     Lisp_Object tem, list = Qnil;
540     NSFontDescriptor *fdesc, *desc;
541     NSMutableSet *fkeys;
542     NSArray *matchingDescs;
543     NSEnumerator *dEnum;
544     NSString *family;
545     NSSet *cFamilies;
546     BOOL foundItal = NO;
548     block_input ();
549     if (NSFONT_TRACE)
550       {
551         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
552                  (isMatch ? "match" : "list"));
553         debug_print (font_spec);
554       }
556     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
558     fdesc = ns_spec_to_descriptor (font_spec);
559     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
560     if (isMatch)
561         [fkeys removeObject: NSFontFamilyAttribute];
563     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
565     if (NSFONT_TRACE)
566         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
567               [matchingDescs count]);
569     for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
570       {
571         if (![cFamilies containsObject:
572                  [desc objectForKey: NSFontFamilyAttribute]])
573             continue;
574         tem = ns_descriptor_to_entity (desc,
575                                          AREF (font_spec, FONT_EXTRA_INDEX),
576                                        NULL);
577         if (isMatch)
578           return tem;
579         list = Fcons (tem, list);
580         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
581             foundItal = YES;
582       }
584     /* Add synthItal member if needed. */
585     family = [fdesc objectForKey: NSFontFamilyAttribute];
586     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
587       {
588         NSFontDescriptor *s1 = [NSFontDescriptor new];
589         NSFontDescriptor *sDesc
590           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
591               fontDescriptorWithFamily: family];
592         list = Fcons (ns_descriptor_to_entity (sDesc,
593                                          AREF (font_spec, FONT_EXTRA_INDEX),
594                                          "synthItal"), list);
595         [s1 release];
596       }
598     unblock_input ();
600     /* Return something if was a match and nothing found. */
601     if (isMatch)
602       return ns_fallback_entity ();
604     if (NSFONT_TRACE)
605         fprintf (stderr, "    Returning %"pI"d entities.\n",
606                  XINT (Flength (list)));
608     return list;
613 /* ==========================================================================
615     Font driver implementation
617    ========================================================================== */
620 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
621 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
622 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
623 static Lisp_Object nsfont_list_family (Lisp_Object frame);
624 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
625                                  int pixel_size);
626 static void nsfont_close (FRAME_PTR f, struct font *font);
627 static int nsfont_has_char (Lisp_Object entity, int c);
628 static unsigned int nsfont_encode_char (struct font *font, int c);
629 static int nsfont_text_extents (struct font *font, unsigned int *code,
630                                 int nglyphs, struct font_metrics *metrics);
631 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
632                         bool with_background);
634 struct font_driver nsfont_driver =
635   {
636     0,                          /* Qns */
637     1,                          /* case sensitive */
638     nsfont_get_cache,
639     nsfont_list,
640     nsfont_match,
641     nsfont_list_family,
642     NULL,                       /*free_entity */
643     nsfont_open,
644     nsfont_close,
645     NULL,                       /* prepare_face */
646     NULL,                       /* done_face */
647     nsfont_has_char,
648     nsfont_encode_char,
649     nsfont_text_extents,
650     nsfont_draw,
651     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
652                  anchor_point, otf_capability, otf_driver,
653                  start_for_frame, end_for_frame, shape */
654   };
657 /* Return a cache of font-entities on FRAME.  The cache must be a
658    cons whose cdr part is the actual cache area.  */
659 static Lisp_Object
660 nsfont_get_cache (FRAME_PTR frame)
662   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
663   return (dpyinfo->name_list_element);
667 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
668    **list** of font-entities.  This and match () are sole APIs that allocate
669    font-entities.  Properties to be considered (2009/05/19) are:
670    regular: foundry, family, adstyle, registry
671    extended: script, lang, otf
672   "Extended" properties are not part of the vector but get stored as
673    lisp properties under FONT_EXTRA_INDEX.
675    The returned entities should have type set (to 'ns), plus the following:
676    foundry, family, adstyle, registry,
677    weight, slant, width, size (0 if scalable),
678    dpi, spacing, avgwidth (0 if scalable)  */
679 static Lisp_Object
680 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
682     return ns_findfonts (font_spec, NO);
686 /* Return a font entity most closely matching with FONT_SPEC on
687    FRAME.  The closeness is determined by the font backend, thus
688    `face-font-selection-order' is ignored here.
689    Properties to be considered are same as for list(). */
690 static Lisp_Object
691 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
693     return ns_findfonts(font_spec, YES);
697 /* List available families.  The value is a list of family names
698    (symbols). */
699 static Lisp_Object
700 nsfont_list_family (Lisp_Object frame)
702   Lisp_Object list = Qnil;
703   NSEnumerator *families;
704   NSString *family;
706   block_input ();
707   families = [[[NSFontManager sharedFontManager] availableFontFamilies]
708                objectEnumerator];
709   while ((family = [families nextObject]))
710       list = Fcons (intern ([family UTF8String]), list);
711   /* FIXME: escape the name? */
713   if (NSFONT_TRACE)
714     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
715              XINT (Flength (list)));
717   unblock_input ();
718   return list;
722 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
723    scalable, open it with PIXEL_SIZE.  */
724 static Lisp_Object
725 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
727   BOOL synthItal;
728   unsigned int traits = 0;
729   struct nsfont_info *font_info;
730   struct font *font;
731   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
732   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
733   NSString *family;
734   NSFont *nsfont, *sfont;
735   Lisp_Object tem;
736   NSRect brect;
737   Lisp_Object font_object;
738   int fixLeopardBug;
740   block_input ();
742   if (NSFONT_TRACE)
743     {
744       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
745       debug_print (font_entity);
746     }
748   if (pixel_size <= 0)
749     {
750       /* try to get it out of frame params */
751         Lisp_Object tem = get_frame_param (f, Qfontsize);
752         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
753     }
755   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
756   synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
757                                        9);
758   family = ns_get_family (font_entity);
759   if (family == nil)
760     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
761   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
762      when setting family in ns_spec_to_descriptor(). */
763   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
764       traits |= NSBoldFontMask;
765   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
766       traits |= NSItalicFontMask;
768   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
769   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
770   nsfont = [fontMgr fontWithFamily: family
771                             traits: traits weight: fixLeopardBug
772                               size: pixel_size];
773   /* if didn't find, try synthetic italic */
774   if (nsfont == nil && synthItal)
775     {
776       nsfont = [fontMgr fontWithFamily: family
777                                 traits: traits & ~NSItalicFontMask
778                                 weight: fixLeopardBug size: pixel_size];
779     }
780 #ifdef NS_IMPL_COCOA
781   /* LastResort not really a family */
782   if (nsfont == nil && [@"LastResort" isEqualToString: family])
783       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
784 #endif
786   if (nsfont == nil)
787     {
788       message_with_string ("*** Warning: font in family '%s' not found",
789                           build_string ([family UTF8String]), 1);
790       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
791     }
793   if (NSFONT_TRACE)
794     NSLog (@"%@\n", nsfont);
796   font_object = font_make_object (VECSIZE (struct nsfont_info),
797                                   font_entity, pixel_size);
798   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
799   font = (struct font *) font_info;
800   if (!font)
801     {
802       unblock_input ();
803       return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
804     }
806   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
807   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
809   /* for metrics */
810 #ifdef NS_IMPL_COCOA
811   sfont = [nsfont screenFontWithRenderingMode:
812                     NSFontAntialiasedIntegerAdvancementsRenderingMode];
813 #else
814   sfont = [nsfont screenFont];
815 #endif
817   if (sfont == nil)
818     sfont = nsfont;
820   /* non-metric backend font struct fields */
821   font = (struct font *) font_info;
822   font->pixel_size = [sfont pointSize];
823   font->driver = &nsfont_driver;
824   font->encoding_charset = -1;
825   font->repertory_charset = -1;
826   font->default_ascent = 0;
827   font->vertical_centering = 0;
828   font->baseline_offset = 0;
829   font->relative_compose = 0;
830   font->font_encoder = NULL;
832   font->props[FONT_FORMAT_INDEX] = Qns;
833   font->props[FONT_FILE_INDEX] = Qnil;
835   {
836     const char *fontName = [[nsfont fontName] UTF8String];
838     /* The values specified by fonts are not always exact. For
839      * example, a 6x8 font could specify that the descender is
840      * -2.00000405... (represented by 0xc000000220000000).  Without
841      * adjustment, the code below would round the descender to -3,
842      * resulting in a font that would be one pixel higher than
843      * intended. */
844     CGFloat adjusted_descender = [sfont descender] + 0.0001;
846 #ifdef NS_IMPL_GNUSTEP
847     font_info->nsfont = sfont;
848 #else
849     font_info->nsfont = nsfont;
850 #endif
851     [font_info->nsfont retain];
853     /* set up ns_font (defined in nsgui.h) */
854     font_info->name = xstrdup (fontName);
855     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
856     font_info->ital =
857       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
859     /* Metrics etc.; some fonts return an unusually large max advance, so we
860        only use it for fonts that have wide characters. */
861     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
862       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
864     brect =  [sfont boundingRectForFont];
866     font_info->underpos = [sfont underlinePosition];
867     font_info->underwidth = [sfont underlineThickness];
868     font_info->size = font->pixel_size;
870     /* max bounds */
871     font_info->max_bounds.ascent = lrint ([sfont ascender]);
872     /* Descender is usually negative.  Use floor to avoid
873        clipping descenders. */
874     font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
875     font_info->height =
876       font_info->max_bounds.ascent + font_info->max_bounds.descent;
877     font_info->max_bounds.width = lrint (font_info->width);
878     font_info->max_bounds.lbearing = lrint (brect.origin.x);
879     font_info->max_bounds.rbearing =
880       lrint (brect.size.width - font_info->width);
882 #ifdef NS_IMPL_COCOA
883     /* set up synthItal and the CG font */
884     font_info->synthItal = synthItal;
885     {
886       ATSFontRef atsFont = ATSFontFindFromPostScriptName
887         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
889       if (atsFont == kATSFontRefUnspecified)
890         {
891           /* see if we can get it by dropping italic (then synthesizing) */
892           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
893               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
894                 fontName], kATSOptionFlagsDefault);
895           if (atsFont != kATSFontRefUnspecified)
896               font_info->synthItal = YES;
897           else
898             {
899               /* last resort fallback */
900               atsFont = ATSFontFindFromPostScriptName
901                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
902             }
903         }
904       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
905     }
906 #endif
908     /* set up metrics portion of font struct */
909     font->ascent = lrint([sfont ascender]);
910     font->descent = -lrint(floor(adjusted_descender));
911     font->space_width = lrint (ns_char_width (sfont, ' '));
912     font->max_width = lrint (font_info->max_bounds.width);
913     font->min_width = font->space_width;  /* Approximate.  */
914     font->average_width = ns_ascii_average_width (sfont);
916     font->height = lrint (font_info->height);
917     font->underline_position = lrint (font_info->underpos);
918     font->underline_thickness = lrint (font_info->underwidth);
920     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
921     font->props[FONT_FULLNAME_INDEX] =
922       make_unibyte_string (font_info->name, strlen (font_info->name));
923   }
924   unblock_input ();
926   return font_object;
930 /* Close FONT on frame F. */
931 static void
932 nsfont_close (FRAME_PTR f, struct font *font)
934   struct nsfont_info *font_info = (struct nsfont_info *)font;
935   int i;
937   /* FIXME: this occurs apparently due to same failure to detect same font
938             that causes need for cache in nsfont_open () */
939   if (!font_info)
940       return;
942   for (i =0; i<0x100; i++)
943     {
944       xfree (font_info->glyphs[i]);
945       xfree (font_info->metrics[i]);
946     }
947   [font_info->nsfont release];
948 #ifdef NS_IMPL_COCOA
949   CGFontRelease (font_info->cgfont);
950 #endif
951   xfree (font_info->name);
952   xfree (font_info);
956 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
957    return 1.  If not, return 0.  If a font must be opened to check
958    it, return -1. */
959 static int
960 nsfont_has_char (Lisp_Object entity, int c)
962   return -1;
966 /* Return a glyph code of FONT for character C (Unicode code point).
967    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
968 static unsigned int
969 nsfont_encode_char (struct font *font, int c)
971   struct nsfont_info *font_info = (struct nsfont_info *)font;
972   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
973   unsigned short g;
975   if (c > 0xFFFF)
976     return FONT_INVALID_CODE;
978   /* did we already cache this block? */
979   if (!font_info->glyphs[high])
980     ns_uni_to_glyphs (font_info, high);
982   g = font_info->glyphs[high][low];
983   return g == 0xFFFF ? FONT_INVALID_CODE : g;
987 /* Perform the size computation of glyphs of FONT and fill in members
988    of METRICS.  The glyphs are specified by their glyph codes in
989    CODE (length NGLYPHS). */
990 static int
991 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
992                      struct font_metrics *metrics)
994   struct nsfont_info *font_info = (struct nsfont_info *)font;
995   struct font_metrics *pcm;
996   unsigned char high, low;
997   int totalWidth = 0;
998   int i;
1000   memset (metrics, 0, sizeof (struct font_metrics));
1002   for (i =0; i<nglyphs; i++)
1003     {
1004       /* get metrics for this glyph, filling cache if need be */
1005       /* TODO: get metrics for whole string from an NSLayoutManager
1006                (if not too slow) */
1007       high = (code[i] & 0xFF00) >> 8;
1008       low = code[i] & 0x00FF;
1009       if (!font_info->metrics[high])
1010         ns_glyph_metrics (font_info, high);
1011       pcm = &(font_info->metrics[high][low]);
1013       if (metrics->lbearing > totalWidth + pcm->lbearing)
1014         metrics->lbearing = totalWidth + pcm->lbearing;
1015       if (metrics->rbearing < totalWidth + pcm->rbearing)
1016         metrics->rbearing = totalWidth + pcm->rbearing;
1017       if (metrics->ascent < pcm->ascent)
1018         metrics->ascent = pcm->ascent;
1019       if (metrics->descent < pcm->descent)
1020         metrics->descent = pcm->descent;
1022       totalWidth += pcm->width;
1023     }
1025   metrics->width = totalWidth;
1027   return totalWidth; /* not specified in doc, but xfont.c does it */
1031 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1032    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND,
1033    fill the background in advance.  It is assured that WITH_BACKGROUND
1034    is false when (FROM > 0 || TO < S->nchars). */
1035 static int
1036 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1037              bool with_background)
1038 /* NOTE: focus and clip must be set
1039      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1041   static char cbuf[1024];
1042   char *c = cbuf;
1043 #ifdef NS_IMPL_GNUSTEP
1044   static float advances[1024];
1045   float *adv = advances;
1046 #else
1047   static CGSize advances[1024];
1048   CGSize *adv = advances;
1049 #endif
1050   struct face *face;
1051   NSRect r;
1052   struct nsfont_info *font = ns_tmp_font;
1053   NSColor *col, *bgCol;
1054   unsigned short *t = s->char2b;
1055   int i, len;
1056   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1057   int end = isComposite ? s->cmp_to : s->nchars;
1059   block_input ();
1060   /* Select face based on input flags */
1061   switch (ns_tmp_flags)
1062     {
1063     case NS_DUMPGLYPH_CURSOR:
1064       face = s->face;
1065       break;
1066     case NS_DUMPGLYPH_MOUSEFACE:
1067       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1068       if (!face)
1069         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1070       break;
1071     default:
1072       face = s->face;
1073     }
1075   r.origin.x = s->x;
1076   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1077     r.origin.x += abs (s->face->box_line_width);
1079   r.origin.y = s->y;
1080   r.size.height = FONT_HEIGHT (font);
1082   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1083      NS to render the string, it will come out differently from the individual
1084      character widths added up because of layout processing. */
1085   {
1086     int cwidth, twidth = 0;
1087     int hi, lo;
1088     /* FIXME: composition: no vertical displacement is considered. */
1089     t += s->cmp_from; /* advance into composition */
1090     for (i = s->cmp_from; i < end; i++, t++)
1091       {
1092         hi = (*t & 0xFF00) >> 8;
1093         lo = *t & 0x00FF;
1094         if (isComposite)
1095           {
1096             if (!s->first_glyph->u.cmp.automatic)
1097                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1098             else
1099               {
1100                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1101                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1102                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1103                     cwidth = LGLYPH_WIDTH (glyph);
1104                 else
1105                   {
1106                     cwidth = LGLYPH_WADJUST (glyph);
1107 #ifdef NS_IMPL_GNUSTEP
1108                     *(adv-1) += LGLYPH_XOFF (glyph);
1109 #else
1110                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1111 #endif
1112                   }
1113               }
1114           }
1115         else
1116           {
1117             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1118               ns_glyph_metrics (font, hi);
1119             cwidth = font->metrics[hi][lo].width;
1120           }
1121         twidth += cwidth;
1122 #ifdef NS_IMPL_GNUSTEP
1123         *adv++ = cwidth;
1124         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1125 #else
1126         (*adv++).width = cwidth;
1127 #endif
1128       }
1129     len = adv - advances;
1130     r.size.width = twidth;
1131     *c = 0;
1132   }
1134   /* fill background if requested */
1135   if (with_background && !isComposite)
1136     {
1137       NSRect br = r;
1138       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1139       int mbox_line_width = max (s->face->box_line_width, 0);
1141       if (s->row->full_width_p)
1142         {
1143           if (br.origin.x <= fibw + 1 + mbox_line_width)
1144             {
1145               br.size.width += br.origin.x - mbox_line_width;
1146               br.origin.x = mbox_line_width;
1147             }
1148           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1149                 <= fibw+1)
1150             br.size.width += fibw;
1151         }
1152       if (s->face->box == FACE_NO_BOX)
1153         {
1154           /* expand unboxed top row over internal border */
1155           if (br.origin.y <= fibw + 1 + mbox_line_width)
1156             {
1157               br.size.height += br.origin.y;
1158               br.origin.y = 0;
1159             }
1160         }
1161       else
1162         {
1163           int correction = abs (s->face->box_line_width)+1;
1164           br.origin.y += correction;
1165           br.size.height -= 2*correction;
1166           br.origin.x += correction;
1167           br.size.width -= 2*correction;
1168         }
1170       if (!s->face->stipple)
1171         [(NS_FACE_BACKGROUND (face) != 0
1172           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1173           : FRAME_BACKGROUND_COLOR (s->f)) set];
1174       else
1175         {
1176           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1177           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1178         }
1179       NSRectFill (br);
1180     }
1183   /* set up for character rendering */
1184   r.origin.y = s->ybase;
1186   col = (NS_FACE_FOREGROUND (face) != 0
1187          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1188          : FRAME_FOREGROUND_COLOR (s->f));
1189   /* FIXME: find another way to pass this */
1190   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1191            : (NS_FACE_BACKGROUND (face) != 0
1192               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1193               : FRAME_BACKGROUND_COLOR (s->f)));
1195   /* render under GNUstep using DPS */
1196 #ifdef NS_IMPL_GNUSTEP
1197   {
1198     NSGraphicsContext *context = GSCurrentContext ();
1200     DPSgsave (context);
1201     [font->nsfont set];
1203     /* do erase if "foreground" mode */
1204     if (bgCol != nil)
1205       {
1206         [bgCol set];
1207         DPSmoveto (context, r.origin.x, r.origin.y);
1208 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1209         DPSxshow (context, cbuf, advances, len);
1210         DPSstroke (context);
1211         [col set];
1212 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1213       }
1215     [col set];
1217     /* draw with DPSxshow () */
1218     DPSmoveto (context, r.origin.x, r.origin.y);
1219     DPSxshow (context, cbuf, advances, len);
1220     DPSstroke (context);
1222     DPSgrestore (context);
1223   }
1225 #else  /* NS_IMPL_COCOA */
1226   {
1227     CGContextRef gcontext =
1228       [[NSGraphicsContext currentContext] graphicsPort];
1229     static CGAffineTransform fliptf;
1230     static BOOL firstTime = YES;
1232     if (firstTime)
1233       {
1234         firstTime = NO;
1235         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1236       }
1238     CGContextSaveGState (gcontext);
1240     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1242     CGContextSetFont (gcontext, font->cgfont);
1243     CGContextSetFontSize (gcontext, font->size);
1244     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1245       CGContextSetShouldAntialias (gcontext, 0);
1246     else
1247       CGContextSetShouldAntialias (gcontext, 1);
1249     CGContextSetTextMatrix (gcontext, fliptf);
1251     if (bgCol != nil)
1252       {
1253         /* foreground drawing; erase first to avoid overstrike */
1254         [bgCol set];
1255         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1256         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1257         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1258         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1259       }
1261     [col set];
1263     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1264     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1265                                     advances, len);
1267     if (face->overstrike)
1268       {
1269         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1270         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1271                                         advances, len);
1272       }
1274     CGContextRestoreGState (gcontext);
1275   }
1276 #endif  /* NS_IMPL_COCOA */
1278   /* Draw underline, overline, strike-through. */
1279   ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1281   unblock_input ();
1282   return to-from;
1287 /* ==========================================================================
1289     Font glyph and metrics caching functions
1291    ========================================================================== */
1293 /* Find and cache corresponding glyph codes for unicode values in given
1294    hi-byte block of 256. */
1295 static void
1296 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1298 #ifdef NS_IMPL_COCOA
1299   static EmacsGlyphStorage *glyphStorage;
1300   static char firstTime = 1;
1301 #endif
1302   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1303   unsigned int i, g, idx;
1304   unsigned short *glyphs;
1306   if (NSFONT_TRACE)
1307     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1308             font_info, block);
1310   block_input ();
1312 #ifdef NS_IMPL_COCOA
1313   if (firstTime)
1314     {
1315       firstTime = 0;
1316       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1317     }
1318 #endif
1320   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1321   if (!unichars || !(font_info->glyphs[block]))
1322     emacs_abort ();
1324   /* create a string containing all Unicode characters in this block */
1325   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1326     if (idx < 0xD800 || idx > 0xDFFF)
1327       unichars[i] = idx;
1328     else
1329       unichars[i] = 0xFEFF;
1330   unichars[0x100] = 0;
1332   {
1333 #ifdef NS_IMPL_COCOA
1334     NSString *allChars = [[NSString alloc]
1335                                initWithCharactersNoCopy: unichars
1336                                                  length: 0x100
1337                                            freeWhenDone: NO];
1338     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1339     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1340     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1341     NSUInteger gInd = 0, cInd = 0;
1343     [glyphStorage setString: allChars font: font_info->nsfont];
1344     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1345                         desiredNumberOfCharacters: glyphStorage->maxChar
1346                                        glyphIndex: &gInd characterIndex: &cInd];
1347 #endif
1348     glyphs = font_info->glyphs[block];
1349     for (i = 0; i < 0x100; i++, glyphs++)
1350       {
1351 #ifdef NS_IMPL_GNUSTEP
1352         g = unichars[i];
1353 #else
1354         g = glyphStorage->cglyphs[i];
1355         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1356         if (g > numGlyphs)
1357           g = 0xFFFF; /* hopefully unused... */
1358 #endif
1359         *glyphs = g;
1360       }
1362 #ifdef NS_IMPL_COCOA
1363     [allChars release];
1364 #endif
1365   }
1367   unblock_input ();
1368   xfree (unichars);
1372 /* Determine and cache metrics for corresponding glyph codes in given
1373    hi-byte block of 256. */
1374 static void
1375 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1377   unsigned int i, g;
1378   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1379   NSFont *sfont;
1380   struct font_metrics *metrics;
1382   if (NSFONT_TRACE)
1383     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1384             font_info, block);
1386 #ifdef NS_IMPL_GNUSTEP
1387   /* not implemented yet (as of startup 0.18), so punt */
1388   if (numGlyphs == 0)
1389     numGlyphs = 0x10000;
1390 #endif
1392   block_input ();
1393 #ifdef NS_IMPL_COCOA
1394   sfont = [font_info->nsfont screenFontWithRenderingMode:
1395                       NSFontAntialiasedIntegerAdvancementsRenderingMode];
1396 #else
1397   sfont = [font_info->nsfont screenFont];
1398 #endif
1400   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1401   if (!(font_info->metrics[block]))
1402     emacs_abort ();
1404   metrics = font_info->metrics[block];
1405   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1406     {
1407       float w, lb, rb;
1408       NSRect r = [sfont boundingRectForGlyph: g];
1410       w = max ([sfont advancementForGlyph: g].width, 2.0);
1411       metrics->width = lrint (w);
1413       lb = r.origin.x;
1414       rb = r.size.width - w;
1415       // Add to bearing for LCD smoothing.  We don't know if it is there.
1416       if (lb < 0)
1417         metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1418       if (font_info->ital)
1419         rb += 0.22 * font_info->height;
1420       metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1422       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1423  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1424       metrics->ascent = r.size.height - metrics->descent;
1425 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1426     }
1427   unblock_input ();
1431 #ifdef NS_IMPL_COCOA
1432 /* helper for font glyph setup */
1433 @implementation EmacsGlyphStorage
1435 - init
1437   return [self initWithCapacity: 1024];
1440 - initWithCapacity: (unsigned long) c
1442   self = [super init];
1443   maxChar = 0;
1444   maxGlyph = 0;
1445   dict = [NSMutableDictionary new];
1446   cglyphs = xmalloc (c * sizeof (CGGlyph));
1447   return self;
1450 - (void) dealloc
1452   if (attrStr != nil)
1453     [attrStr release];
1454   [dict release];
1455   xfree (cglyphs);
1456   [super dealloc];
1459 - (void) setString: (NSString *)str font: (NSFont *)font
1461   [dict setObject: font forKey: NSFontAttributeName];
1462   if (attrStr != nil)
1463     [attrStr release];
1464   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1465   maxChar = [str length];
1466   maxGlyph = 0;
1469 /* NSGlyphStorage protocol */
1470 - (NSUInteger)layoutOptions
1472   return 0;
1475 - (NSAttributedString *)attributedString
1477   return attrStr;
1480 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1481         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1482         characterIndex: (NSUInteger)charIndex
1484   len = glyphIndex+length;
1485   for (i =glyphIndex; i<len; i++)
1486     cglyphs[i] = glyphs[i-glyphIndex];
1487   if (len > maxGlyph)
1488     maxGlyph = len;
1491 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1492         forGlyphAtIndex: (NSUInteger)glyphIndex
1494   return;
1497 @end
1498 #endif /* NS_IMPL_COCOA */
1501 /* Debugging */
1502 void
1503 ns_dump_glyphstring (struct glyph_string *s)
1505   int i;
1507   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1508 "overlap = %d, bg_filled = %d:",
1509            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1510            s->row->overlapping_p, s->background_filled_p);
1511   for (i =0; i<s->nchars; i++)
1512     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1513   fprintf (stderr, "\n");
1517 void
1518 syms_of_nsfont (void)
1520   nsfont_driver.type = Qns;
1521   register_font_driver (&nsfont_driver, NULL);
1522   DEFSYM (Qcondensed, "condensed");
1523   DEFSYM (Qexpanded, "expanded");
1524   DEFSYM (Qapple, "apple");
1525   DEFSYM (Qroman, "roman");
1526   DEFSYM (Qmedium, "medium");
1527   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1528                doc: /* Internal use: maps font registry to Unicode script. */);
1530   ascii_printable = NULL;