Fix problems found by static checking --with-ns
[emacs.git] / src / nsfont.m
blobbe7d2ec36b9402faf89845313cb5c8273017185e
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006-2016 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 (at
10 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 "character.h"
37 #include "font.h"
38 #include "termchar.h"
40 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
41 #ifdef NS_IMPL_GNUSTEP
42 #import <AppKit/NSFontDescriptor.h>
43 #endif
45 #define NSFONT_TRACE 0
46 #define LCD_SMOOTHING_MARGIN 2
48 /* font glyph and metrics caching functions, implemented at end */
49 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
50                               unsigned char block);
51 static void ns_glyph_metrics (struct nsfont_info *font_info,
52                               unsigned char block);
54 #define INVALID_GLYPH 0xFFFF
56 /* ==========================================================================
58     Utilities
60    ========================================================================== */
63 /* Replace spaces w/another character so emacs core font parsing routines
64    aren't thrown off. */
65 static void
66 ns_escape_name (char *name)
68   for (; *name; name++)
69     if (*name == ' ')
70       *name = '_';
74 /* Reconstruct spaces in a font family name passed through emacs. */
75 static void
76 ns_unescape_name (char *name)
78   for (; *name; name++)
79     if (*name == '_')
80       *name = ' ';
84 /* Extract family name from a font spec. */
85 static NSString *
86 ns_get_family (Lisp_Object font_spec)
88   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
89   if (NILP (tem))
90       return nil;
91   else
92     {
93       char *tmp = xlispstrdup (SYMBOL_NAME (tem));
94       NSString *family;
95       ns_unescape_name (tmp);
96       family = [NSString stringWithUTF8String: tmp];
97       xfree (tmp);
98       return family;
99     }
103 /* Return 0 if attr not set, else value (which might also be 0).
104    On Leopard 0 gets returned even on descriptors where the attribute
105    was never set, so there's no way to distinguish between unspecified
106    and set to not have.  Callers should assume 0 means unspecified. */
107 static float
108 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
110     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
111     NSNumber *val = [tdict objectForKey: trait];
112     return val == nil ? 0.0F : [val floatValue];
116 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
117    to NSFont descriptor.  Information under extra only needed for matching. */
118 #define STYLE_REF 100
119 static NSFontDescriptor *
120 ns_spec_to_descriptor (Lisp_Object font_spec)
122     NSFontDescriptor *fdesc;
123     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
124     NSMutableDictionary *tdict = [NSMutableDictionary new];
125     NSString *family = ns_get_family (font_spec);
126     float n;
128     /* add each attr in font_spec to fdAttrs.. */
129     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
130     if (n != -1 && n != STYLE_REF)
131         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
132                   forKey: NSFontWeightTrait];
133     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
134     if (n != -1 && n != STYLE_REF)
135         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
136                   forKey: NSFontSlantTrait];
137     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
138     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
139         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
140                   forKey: NSFontWidthTrait];
141     if ([tdict count] > 0)
142         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
144     fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
145                retain] autorelease];
147     if (family != nil)
148       {
149         NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
150         fdesc = [[fdesc2 retain] autorelease];
151       }
153     [fdAttrs release];
154     [tdict release];
155     return fdesc;
159 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
160 static Lisp_Object
161 ns_descriptor_to_entity (NSFontDescriptor *desc,
162                          Lisp_Object extra,
163                          const char *style)
165     Lisp_Object font_entity = font_make_entity ();
166     /*   NSString *psName = [desc postscriptName]; */
167     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
168     unsigned int traits = [desc symbolicTraits];
169     char *escapedFamily;
171     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
172     if (family == nil)
173       family = [desc objectForKey: NSFontNameAttribute];
174     if (family == nil)
175       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
177     escapedFamily = xstrdup ([family UTF8String]);
178     ns_escape_name (escapedFamily);
180     ASET (font_entity, FONT_TYPE_INDEX, Qns);
181     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
182     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
183     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
184     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
186     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
187                     traits & NSFontBoldTrait ? Qbold : Qmedium);
188 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
189                     make_number (100 + 100
190                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
191     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
192                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
193 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
194                     make_number (100 + 100
195                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
196     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
197                     traits & NSFontCondensedTrait ? Qcondensed :
198                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
199 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
200                     make_number (100 + 100
201                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
203     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
204     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
205     ASET (font_entity, FONT_SPACING_INDEX,
206           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
207               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
209     ASET (font_entity, FONT_EXTRA_INDEX, extra);
210     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
212     if (NSFONT_TRACE)
213       {
214         fprintf (stderr, "created font_entity:\n    ");
215         debug_print (font_entity);
216       }
218     xfree (escapedFamily);
219     return font_entity;
223 /* Default font entity. */
224 static Lisp_Object
225 ns_fallback_entity (void)
227   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
228       fontDescriptor], Qnil, NULL);
232 /* Utility: get width of a char c in screen font SFONT */
233 static CGFloat
234 ns_char_width (NSFont *sfont, int c)
236   CGFloat w = -1.0;
237   NSString *cstr = [NSString stringWithFormat: @"%c", c];
239 #ifdef NS_IMPL_COCOA
240   NSGlyph glyph = [sfont glyphWithName: cstr];
241   if (glyph)
242     w = [sfont advancementForGlyph: glyph].width;
243 #endif
245   if (w < 0.0)
246     {
247       NSDictionary *attrsDictionary =
248         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
249       w = [cstr sizeWithAttributes: attrsDictionary].width;
250     }
252   return max (w, 1.0);
255 /* Return average width over ASCII printable characters for SFONT.  */
257 static NSString *ascii_printable;
259 static int
260 ns_ascii_average_width (NSFont *sfont)
262   CGFloat w = -1.0;
264   if (!ascii_printable)
265     {
266       char chars[96];
267       int ch;
268       for (ch = 0; ch < 95; ch++)
269         chars[ch] = ' ' + ch;
270       chars[95] = '\0';
272       ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
273     }
275 #ifdef NS_IMPL_COCOA
276   NSGlyph glyph = [sfont glyphWithName: ascii_printable];
277   if (glyph)
278     w = [sfont advancementForGlyph: glyph].width;
279 #endif
281   if (w < (CGFloat) 0.0)
282     {
283       NSDictionary *attrsDictionary =
284         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
285       w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
286     }
288   return lrint (w / (CGFloat) 95.0);
292 /* Return whether set1 covers set2 to a reasonable extent given by pct.
293    We check, out of each 16 Unicode char range containing chars in set2,
294    whether at least one character is present in set1.
295    This must be true for pct of the pairs to consider it covering. */
296 static BOOL
297 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
299     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
300     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
301     int i, off = 0, tot = 0;
303     /* Work around what appears to be a GNUstep bug.
304        See <http://bugs.gnu.org/11853>.  */
305     if (! (bytes1 && bytes2))
306       return NO;
308     for (i=0; i<4096; i++, bytes1++, bytes2++)
309         if (*bytes2)
310           {
311             tot++;
312             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
313                 off++;
314           }
315 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
316     return (float)off / tot < 1.0F - pct;
320 /* Convert :lang property to a script.  Use of :lang property by font backend
321    seems to be limited for now (2009/05) to ja, zh, and ko. */
322 static NSString
323 *ns_lang_to_script (Lisp_Object lang)
325     if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
326         return @"han";
327     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
328              have more characters. */
329     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
330         return @"han";
331     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
332         return @"hangul";
333     else
334         return @"";
338 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
339    everyone just use some standard Unicode names for these?) */
340 static NSString
341 *ns_otf_to_script (Lisp_Object otf)
343     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
344     return CONSP (script)
345         ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
346         : @"";
350 /* Convert a font registry, such as  */
351 static NSString
352 *ns_registry_to_script (char *reg)
354     Lisp_Object script, r, rts = Vns_reg_to_script;
355     while (CONSP (rts))
356       {
357         r = XCAR (XCAR (rts));
358         if (!strncmp (SSDATA (r), reg, SBYTES (r)))
359           {
360             script = XCDR (XCAR (rts));
361             return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
362           }
363         rts = XCDR (rts);
364       }
365     return  @"";
369 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
370    plus registry regular property, for something that can be mapped to a
371    Unicode script.  Empty string returned if no script spec found. */
372 static NSString
373 *ns_get_req_script (Lisp_Object font_spec)
375     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
376     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
378     /* The extra-bundle properties have priority. */
379     for ( ; CONSP (extra); extra = XCDR (extra))
380       {
381         Lisp_Object tmp = XCAR (extra);
382         if (CONSP (tmp))
383           {
384             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
385             if (EQ (key, QCscript) && SYMBOLP (val))
386                 return [NSString stringWithUTF8String:
387                             SSDATA (SYMBOL_NAME (val))];
388             if (EQ (key, QClang) && SYMBOLP (val))
389                 return ns_lang_to_script (val);
390             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
391                 return ns_otf_to_script (val);
392           }
393       }
395     /* If we get here, check the charset portion of the registry. */
396     if (! NILP (reg))
397       {
398         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
399            (which causes box rendering if we don't treat it like iso8858-1)
400            but also for ascii (which causes unnecessary font substitution). */
401 #if 0
402         if (EQ (reg, Qiso10646_1))
403           reg = Qiso8859_1;
404 #endif
405         return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
406       }
408     return @"";
412 /* This small function is static in fontset.c.  If it can be made public for
413    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
414 static void
415 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
417     if (EQ (XCAR (arg), val))
418       {
419         if (CONSP (range))
420           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
421         else
422           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
423       }
427 /* Use the Unicode range information in Vchar_script_table to convert a script
428    name into an NSCharacterSet. */
429 static NSCharacterSet
430 *ns_script_to_charset (NSString *scriptName)
432     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
433     Lisp_Object script = intern ([scriptName UTF8String]);
434     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
436     if (! NILP (Fmemq (script, script_list)))
437       {
438         Lisp_Object ranges, range_list;
440         ranges = list1 (script);
441         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
442                         ranges);
443         range_list = Fnreverse (XCDR (ranges));
444         if (! NILP (range_list))
445           {
446             for (; CONSP (range_list); range_list = XCDR (range_list))
447               {
448                 int start = XINT (XCAR (XCAR (range_list)));
449                 int end = XINT (XCDR (XCAR (range_list)));
450                 if (NSFONT_TRACE)
451                     debug_print (XCAR (range_list));
452                 if (end < 0x10000)
453                     [charset addCharactersInRange:
454                         NSMakeRange (start, end-start)];
455               }
456           }
457       }
458     return charset;
462 /* Return an array of font families containing characters for the given
463    script, for the given coverage criterion, including at least LastResort.
464    Results are cached by script for faster access.
465    If none are found, we reduce the percentage and try again, until 5%.
466    This provides a font with at least some characters if such can be found.
467    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
468    (b) need approximate match as fonts covering full Unicode ranges are rare. */
469 static NSSet
470 *ns_get_covering_families (NSString *script, float pct)
472     static NSMutableDictionary *scriptToFamilies = nil;
473     NSMutableSet *families;
475     if (NSFONT_TRACE)
476         NSLog(@"Request covering families for script: '%@'", script);
478     if (scriptToFamilies == nil)
479         scriptToFamilies = [[NSMutableDictionary alloc] init];
481     if ((families = [scriptToFamilies objectForKey: script]) == nil)
482       {
483         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
484         NSArray *allFamilies = [fontMgr availableFontFamilies];
486         if ([script length] == 0)
487             families = [NSMutableSet setWithArray: allFamilies];
488         else
489           {
490             NSCharacterSet *charset = ns_script_to_charset (script);
491             NSString *family;
492             families = [NSMutableSet setWithCapacity: 10];
493             while (1)
494               {
495                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
496                 while ((family = [allFamiliesEnum nextObject]))
497                   {
498                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
499                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
500                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
501                     if (fset == nil)
502                       fset = [NSCharacterSet characterSetWithRange:
503                                                NSMakeRange (0, 127)];
504                     if (ns_charset_covers(fset, charset, pct))
505                         [families addObject: family];
506                   }
507                 pct -= 0.2F;
508                 if ([families count] > 0 || pct < 0.05F)
509                     break;
510               }
511             [charset release];
512           }
513 #ifdef NS_IMPL_COCOA
514         if ([families count] == 0)
515             [families addObject: @"LastResort"];
516 #endif
517         [scriptToFamilies setObject: families forKey: script];
518       }
520     if (NSFONT_TRACE)
521       NSLog(@"    returning %lu families", (unsigned long)[families count]);
522     return families;
526 /* Implementation for list() and match().  List() can return nil, match()
527 must return something.  Strategy is to drop family name from attribute
528 matching set for match. */
529 static Lisp_Object
530 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
532     Lisp_Object tem, list = Qnil;
533     NSFontDescriptor *fdesc, *desc;
534     NSMutableSet *fkeys;
535     NSArray *matchingDescs;
536     NSEnumerator *dEnum;
537     NSString *family;
538     NSSet *cFamilies;
539     BOOL foundItal = NO;
541     block_input ();
542     if (NSFONT_TRACE)
543       {
544         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
545                  (isMatch ? "match" : "list"));
546         debug_print (font_spec);
547       }
549     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
551     fdesc = ns_spec_to_descriptor (font_spec);
552     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
553     if (isMatch)
554         [fkeys removeObject: NSFontFamilyAttribute];
556     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
558     if (NSFONT_TRACE)
559         NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
560               (unsigned long)[matchingDescs count]);
562     for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
563       {
564         if (![cFamilies containsObject:
565                  [desc objectForKey: NSFontFamilyAttribute]])
566             continue;
567         tem = ns_descriptor_to_entity (desc,
568                                          AREF (font_spec, FONT_EXTRA_INDEX),
569                                        NULL);
570         if (isMatch)
571           return tem;
572         list = Fcons (tem, list);
573         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
574             foundItal = YES;
575       }
577     /* Add synthItal member if needed. */
578     family = [fdesc objectForKey: NSFontFamilyAttribute];
579     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
580       {
581         NSFontDescriptor *s1 = [NSFontDescriptor new];
582         NSFontDescriptor *sDesc
583           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
584               fontDescriptorWithFamily: family];
585         list = Fcons (ns_descriptor_to_entity (sDesc,
586                                          AREF (font_spec, FONT_EXTRA_INDEX),
587                                          "synthItal"), list);
588         [s1 release];
589       }
591     unblock_input ();
593     /* Return something if was a match and nothing found. */
594     if (isMatch)
595       return ns_fallback_entity ();
597     if (NSFONT_TRACE)
598         fprintf (stderr, "    Returning %"pI"d entities.\n",
599                  XINT (Flength (list)));
601     return list;
606 /* ==========================================================================
608     Font driver implementation
610    ========================================================================== */
613 static Lisp_Object nsfont_get_cache (struct frame *frame);
614 static Lisp_Object nsfont_list (struct frame *, Lisp_Object);
615 static Lisp_Object nsfont_match (struct frame *, Lisp_Object);
616 static Lisp_Object nsfont_list_family (struct frame *);
617 static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity,
618                                  int pixel_size);
619 static void nsfont_close (struct font *font);
620 static int nsfont_has_char (Lisp_Object entity, int c);
621 static unsigned int nsfont_encode_char (struct font *font, int c);
622 static void nsfont_text_extents (struct font *font, unsigned int *code,
623                                  int nglyphs, struct font_metrics *metrics);
624 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
625                         bool with_background);
627 struct font_driver nsfont_driver =
628   {
629     0,                          /* Qns */
630     1,                          /* case sensitive */
631     nsfont_get_cache,
632     nsfont_list,
633     nsfont_match,
634     nsfont_list_family,
635     NULL,                       /*free_entity */
636     nsfont_open,
637     nsfont_close,
638     NULL,                       /* prepare_face */
639     NULL,                       /* done_face */
640     nsfont_has_char,
641     nsfont_encode_char,
642     nsfont_text_extents,
643     nsfont_draw,
644     /* excluded: get_bitmap, free_bitmap,
645                  anchor_point, otf_capability, otf_driver,
646                  start_for_frame, end_for_frame, shape */
647   };
650 /* Return a cache of font-entities on FRAME.  The cache must be a
651    cons whose cdr part is the actual cache area.  */
652 static Lisp_Object
653 nsfont_get_cache (struct frame *frame)
655   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (frame);
656   return (dpyinfo->name_list_element);
660 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
661    **list** of font-entities.  This and match () are sole APIs that allocate
662    font-entities.  Properties to be considered (2009/05/19) are:
663    regular: foundry, family, adstyle, registry
664    extended: script, lang, otf
665   "Extended" properties are not part of the vector but get stored as
666    lisp properties under FONT_EXTRA_INDEX.
668    The returned entities should have type set (to 'ns), plus the following:
669    foundry, family, adstyle, registry,
670    weight, slant, width, size (0 if scalable),
671    dpi, spacing, avgwidth (0 if scalable)  */
672 static Lisp_Object
673 nsfont_list (struct frame *f, Lisp_Object font_spec)
675   return ns_findfonts (font_spec, NO);
679 /* Return a font entity most closely matching with FONT_SPEC on
680    FRAME.  The closeness is determined by the font backend, thus
681    `face-font-selection-order' is ignored here.
682    Properties to be considered are same as for list(). */
683 static Lisp_Object
684 nsfont_match (struct frame *f, Lisp_Object font_spec)
686   return ns_findfonts (font_spec, YES);
690 /* List available families.  The value is a list of family names
691    (symbols). */
692 static Lisp_Object
693 nsfont_list_family (struct frame *f)
695   Lisp_Object list = Qnil;
696   NSEnumerator *families;
697   NSString *family;
699   block_input ();
700   families = [[[NSFontManager sharedFontManager] availableFontFamilies]
701                objectEnumerator];
702   while ((family = [families nextObject]))
703       list = Fcons (intern ([family UTF8String]), list);
704   /* FIXME: escape the name? */
706   if (NSFONT_TRACE)
707     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
708              XINT (Flength (list)));
710   unblock_input ();
711   return list;
715 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
716    scalable, open it with PIXEL_SIZE.  */
717 static Lisp_Object
718 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
720   BOOL synthItal;
721   unsigned int traits = 0;
722   struct nsfont_info *font_info;
723   struct font *font;
724   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
725   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
726   NSString *family;
727   NSFont *nsfont, *sfont;
728   Lisp_Object tem;
729   NSRect brect;
730   Lisp_Object font_object;
731   int fixLeopardBug;
733   block_input ();
735   if (NSFONT_TRACE)
736     {
737       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
738       debug_print (font_entity);
739     }
741   if (pixel_size <= 0)
742     {
743       /* try to get it out of frame params */
744         Lisp_Object tem = get_frame_param (f, Qfontsize);
745         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
746     }
748   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
749   synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
750                                        9);
751   family = ns_get_family (font_entity);
752   if (family == nil)
753     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
754   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
755      when setting family in ns_spec_to_descriptor(). */
756   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
757       traits |= NSBoldFontMask;
758   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
759       traits |= NSItalicFontMask;
761   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
762   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
763   nsfont = [fontMgr fontWithFamily: family
764                             traits: traits weight: fixLeopardBug
765                               size: pixel_size];
766   /* if didn't find, try synthetic italic */
767   if (nsfont == nil && synthItal)
768     {
769       nsfont = [fontMgr fontWithFamily: family
770                                 traits: traits & ~NSItalicFontMask
771                                 weight: fixLeopardBug size: pixel_size];
772     }
773 #ifdef NS_IMPL_COCOA
774   /* LastResort not really a family */
775   if (nsfont == nil && [@"LastResort" isEqualToString: family])
776       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
777 #endif
779   if (nsfont == nil)
780     {
781       message_with_string ("*** Warning: font in family `%s' not found",
782                           build_string ([family UTF8String]), 1);
783       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
784     }
786   if (NSFONT_TRACE)
787     NSLog (@"%@\n", nsfont);
789   font_object = font_make_object (VECSIZE (struct nsfont_info),
790                                   font_entity, pixel_size);
791   ASET (font_object, FONT_TYPE_INDEX, nsfont_driver.type);
792   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
793   font = (struct font *) font_info;
794   if (!font)
795     {
796       unblock_input ();
797       return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
798     }
800   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
801   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
803   /* for metrics */
804 #ifdef NS_IMPL_COCOA
805   sfont = [nsfont screenFontWithRenderingMode:
806                     NSFontAntialiasedIntegerAdvancementsRenderingMode];
807 #else
808   sfont = [nsfont screenFont];
809 #endif
811   if (sfont == nil)
812     sfont = nsfont;
814   /* non-metric backend font struct fields */
815   font = (struct font *) font_info;
816   font->pixel_size = [sfont pointSize];
817   font->driver = &nsfont_driver;
818   font->encoding_charset = -1;
819   font->repertory_charset = -1;
820   font->default_ascent = 0;
821   font->vertical_centering = 0;
822   font->baseline_offset = 0;
823   font->relative_compose = 0;
825   {
826     const char *fontName = [[nsfont fontName] UTF8String];
828     /* The values specified by fonts are not always exact. For
829      * example, a 6x8 font could specify that the descender is
830      * -2.00000405... (represented by 0xc000000220000000).  Without
831      * adjustment, the code below would round the descender to -3,
832      * resulting in a font that would be one pixel higher than
833      * intended. */
834     CGFloat adjusted_descender = [sfont descender] + 0.0001;
836 #ifdef NS_IMPL_GNUSTEP
837     font_info->nsfont = sfont;
838 #else
839     font_info->nsfont = nsfont;
840 #endif
841     [font_info->nsfont retain];
843     /* set up ns_font (defined in nsgui.h) */
844     font_info->name = xstrdup (fontName);
845     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
846     font_info->ital =
847       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
849     /* Metrics etc.; some fonts return an unusually large max advance, so we
850        only use it for fonts that have wide characters. */
851     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
852       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
854     brect =  [sfont boundingRectForFont];
856     font_info->underpos = [sfont underlinePosition];
857     font_info->underwidth = [sfont underlineThickness];
858     font_info->size = font->pixel_size;
860     /* max bounds */
861     font->ascent = font_info->max_bounds.ascent = lrint ([sfont ascender]);
862     /* Descender is usually negative.  Use floor to avoid
863        clipping descenders. */
864     font->descent =
865       font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
866     font_info->height =
867       font_info->max_bounds.ascent + font_info->max_bounds.descent;
868     font_info->max_bounds.width = lrint (font_info->width);
869     font_info->max_bounds.lbearing = lrint (brect.origin.x);
870     font_info->max_bounds.rbearing =
871       lrint (brect.size.width - (CGFloat) font_info->width);
873 #ifdef NS_IMPL_COCOA
874     /* set up synthItal and the CG font */
875     font_info->synthItal = synthItal;
876     {
877       ATSFontRef atsFont = ATSFontFindFromPostScriptName
878         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
880       if (atsFont == kATSFontRefUnspecified)
881         {
882           /* see if we can get it by dropping italic (then synthesizing) */
883           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
884               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
885                 fontName], kATSOptionFlagsDefault);
886           if (atsFont != kATSFontRefUnspecified)
887               font_info->synthItal = YES;
888           else
889             {
890               /* last resort fallback */
891               atsFont = ATSFontFindFromPostScriptName
892                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
893             }
894         }
895       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
896     }
897 #endif
899     /* set up metrics portion of font struct */
900     font->ascent = lrint([sfont ascender]);
901     font->descent = -lrint(floor(adjusted_descender));
902     font->space_width = lrint (ns_char_width (sfont, ' '));
903     font->max_width = lrint (font_info->max_bounds.width);
904     font->min_width = font->space_width;  /* Approximate.  */
905     font->average_width = ns_ascii_average_width (sfont);
907     font->height = lrint (font_info->height);
908     font->underline_position = lrint (font_info->underpos);
909     font->underline_thickness = lrint (font_info->underwidth);
911     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
912     font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
913   }
914   unblock_input ();
916   return font_object;
920 /* Close FONT. */
921 static void
922 nsfont_close (struct font *font)
924   struct nsfont_info *font_info = (struct nsfont_info *) font;
926   /* FIXME: font_info may be NULL due to same failure to detect
927      same font that causes need for cache in nsfont_open.  */
928   if (font_info && font_info->name)
929     {
930       int i;
932       for (i = 0; i < 0x100; i++)
933         {
934           xfree (font_info->glyphs[i]);
935           xfree (font_info->metrics[i]);
936         }
937       xfree (font_info->glyphs);
938       xfree (font_info->metrics);
939       [font_info->nsfont release];
940 #ifdef NS_IMPL_COCOA
941       CGFontRelease (font_info->cgfont);
942 #endif
943       xfree (font_info->name);
944       font_info->name = NULL;
945     }
949 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
950    return 1.  If not, return 0.  If a font must be opened to check
951    it, return -1. */
952 static int
953 nsfont_has_char (Lisp_Object entity, int c)
955   return -1;
959 /* Return a glyph code of FONT for character C (Unicode code point).
960    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
961 static unsigned int
962 nsfont_encode_char (struct font *font, int c)
964   struct nsfont_info *font_info = (struct nsfont_info *)font;
965   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
966   unsigned short g;
968   if (c > 0xFFFF)
969     return FONT_INVALID_CODE;
971   /* did we already cache this block? */
972   if (!font_info->glyphs[high])
973     ns_uni_to_glyphs (font_info, high);
975   g = font_info->glyphs[high][low];
976   return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
980 /* Perform the size computation of glyphs of FONT and fill in members
981    of METRICS.  The glyphs are specified by their glyph codes in
982    CODE (length NGLYPHS). */
983 static void
984 nsfont_text_extents (struct font *font, unsigned int *code,
985                      int nglyphs, struct font_metrics *metrics)
987   struct nsfont_info *font_info = (struct nsfont_info *)font;
988   struct font_metrics *pcm;
989   unsigned char high, low;
990   int totalWidth = 0;
991   int i;
993   memset (metrics, 0, sizeof (struct font_metrics));
995   for (i = 0; i < nglyphs; i++)
996     {
997       /* get metrics for this glyph, filling cache if need be */
998       /* TODO: get metrics for whole string from an NSLayoutManager
999                (if not too slow) */
1000       high = (code[i] & 0xFF00) >> 8;
1001       low = code[i] & 0x00FF;
1002       if (!font_info->metrics[high])
1003         ns_glyph_metrics (font_info, high);
1004       pcm = &(font_info->metrics[high][low]);
1006       if (metrics->lbearing > totalWidth + pcm->lbearing)
1007         metrics->lbearing = totalWidth + pcm->lbearing;
1008       if (metrics->rbearing < totalWidth + pcm->rbearing)
1009         metrics->rbearing = totalWidth + pcm->rbearing;
1010       if (metrics->ascent < pcm->ascent)
1011         metrics->ascent = pcm->ascent;
1012       if (metrics->descent < pcm->descent)
1013         metrics->descent = pcm->descent;
1015       totalWidth += pcm->width;
1016     }
1018   metrics->width = totalWidth;
1022 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1023    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND,
1024    fill the background in advance.  It is assured that WITH_BACKGROUND
1025    is false when (FROM > 0 || TO < S->nchars). */
1026 static int
1027 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1028              bool with_background)
1029 /* NOTE: focus and clip must be set */
1031   static unsigned char cbuf[1024];
1032   unsigned char *c = cbuf;
1033 #ifdef NS_IMPL_GNUSTEP
1034 #if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22
1035   static CGFloat advances[1024];
1036   CGFloat *adv = advances;
1037 #else
1038   static float advances[1024];
1039   float *adv = advances;
1040 #endif
1041 #else
1042   static CGSize advances[1024];
1043   CGSize *adv = advances;
1044 #endif
1045   struct face *face;
1046   NSRect r;
1047   struct nsfont_info *font;
1048   NSColor *col, *bgCol;
1049   unsigned short *t = s->char2b;
1050   int i, len, flags;
1051   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1053   block_input ();
1055   font = (struct nsfont_info *)s->face->font;
1056   if (font == NULL)
1057     font = (struct nsfont_info *)FRAME_FONT (s->f);
1059   /* Select face based on input flags */
1060   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
1061     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
1062      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
1063       NS_DUMPGLYPH_NORMAL));
1065   switch (flags)
1066     {
1067     case NS_DUMPGLYPH_CURSOR:
1068       face = s->face;
1069       break;
1070     case NS_DUMPGLYPH_MOUSEFACE:
1071       face = FACE_FROM_ID_OR_NULL (s->f,
1072                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1073       if (!face)
1074         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1075       break;
1076     default:
1077       face = s->face;
1078     }
1080   r.origin.x = s->x;
1081   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1082     r.origin.x += abs (s->face->box_line_width);
1084   r.origin.y = s->y;
1085   r.size.height = FONT_HEIGHT (font);
1087   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1088      NS to render the string, it will come out differently from the individual
1089      character widths added up because of layout processing. */
1090   {
1091     int cwidth, twidth = 0;
1092     int hi, lo;
1093     /* FIXME: composition: no vertical displacement is considered. */
1094     t += from; /* advance into composition */
1095     for (i = from; i < to; i++, t++)
1096       {
1097         hi = (*t & 0xFF00) >> 8;
1098         lo = *t & 0x00FF;
1099         if (isComposite)
1100           {
1101             if (!s->first_glyph->u.cmp.automatic)
1102                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1103             else
1104               {
1105                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1106                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1107                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1108                     cwidth = LGLYPH_WIDTH (glyph);
1109                 else
1110                   {
1111                     cwidth = LGLYPH_WADJUST (glyph);
1112 #ifdef NS_IMPL_GNUSTEP
1113                     *(adv-1) += LGLYPH_XOFF (glyph);
1114 #else
1115                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1116 #endif
1117                   }
1118               }
1119           }
1120         else
1121           {
1122             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1123               ns_glyph_metrics (font, hi);
1124             cwidth = font->metrics[hi][lo].width;
1125           }
1126         twidth += cwidth;
1127 #ifdef NS_IMPL_GNUSTEP
1128         *adv++ = cwidth;
1129         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1130 #else
1131         (*adv++).width = cwidth;
1132 #endif
1133       }
1134     len = adv - advances;
1135     r.size.width = twidth;
1136     *c = 0;
1137   }
1139   /* fill background if requested */
1140   if (with_background && !isComposite)
1141     {
1142       NSRect br = r;
1143       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1144       int mbox_line_width = max (s->face->box_line_width, 0);
1146       if (s->row->full_width_p)
1147         {
1148           if (br.origin.x <= fibw + 1 + mbox_line_width)
1149             {
1150               br.size.width += br.origin.x - mbox_line_width;
1151               br.origin.x = mbox_line_width;
1152             }
1153           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1154                 <= fibw+1)
1155             br.size.width += fibw;
1156         }
1157       if (s->face->box == FACE_NO_BOX)
1158         {
1159           /* expand unboxed top row over internal border */
1160           if (br.origin.y <= fibw + 1 + mbox_line_width)
1161             {
1162               br.size.height += br.origin.y;
1163               br.origin.y = 0;
1164             }
1165         }
1166       else
1167         {
1168           int correction = abs (s->face->box_line_width)+1;
1169           br.origin.y += correction;
1170           br.size.height -= 2*correction;
1171           br.origin.x += correction;
1172           br.size.width -= 2*correction;
1173         }
1175       if (!s->face->stipple)
1176         [(NS_FACE_BACKGROUND (face) != 0
1177           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1178           : FRAME_BACKGROUND_COLOR (s->f)) set];
1179       else
1180         {
1181           struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
1182           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1183         }
1184       NSRectFill (br);
1185     }
1188   /* set up for character rendering */
1189   r.origin.y = y;
1191   col = (NS_FACE_FOREGROUND (face) != 0
1192          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1193          : FRAME_FOREGROUND_COLOR (s->f));
1195   bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
1196            : (NS_FACE_BACKGROUND (face) != 0
1197               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1198               : FRAME_BACKGROUND_COLOR (s->f)));
1200   /* render under GNUstep using DPS */
1201 #ifdef NS_IMPL_GNUSTEP
1202   {
1203     NSGraphicsContext *context = GSCurrentContext ();
1205     DPSgsave (context);
1206     [font->nsfont set];
1208     /* do erase if "foreground" mode */
1209     if (bgCol != nil)
1210       {
1211         [bgCol set];
1212         DPSmoveto (context, r.origin.x, r.origin.y);
1213 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1214         DPSxshow (context, (const char *) cbuf, advances, len);
1215         DPSstroke (context);
1216         [col set];
1217 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1218       }
1220     [col set];
1222     /* draw with DPSxshow () */
1223     DPSmoveto (context, r.origin.x, r.origin.y);
1224     DPSxshow (context, (const char *) cbuf, advances, len);
1225     DPSstroke (context);
1227     DPSgrestore (context);
1228   }
1230 #else  /* NS_IMPL_COCOA */
1231   {
1232     CGContextRef gcontext =
1233       [[NSGraphicsContext currentContext] graphicsPort];
1234     static CGAffineTransform fliptf;
1235     static BOOL firstTime = YES;
1237     if (firstTime)
1238       {
1239         firstTime = NO;
1240         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1241       }
1243     CGContextSaveGState (gcontext);
1245     // Used to be Fix2X (kATSItalicQDSkew), but Fix2X is deprecated
1246     // and kATSItalicQDSkew is 0.25.
1247     fliptf.c =  font->synthItal ? 0.25 : 0.0;
1249     CGContextSetFont (gcontext, font->cgfont);
1250     CGContextSetFontSize (gcontext, font->size);
1251     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1252       CGContextSetShouldAntialias (gcontext, 0);
1253     else
1254       CGContextSetShouldAntialias (gcontext, 1);
1256     CGContextSetTextMatrix (gcontext, fliptf);
1258     if (bgCol != nil)
1259       {
1260         /* foreground drawing; erase first to avoid overstrike */
1261         [bgCol set];
1262         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1263         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1264         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1265         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1266       }
1268     [col set];
1270     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1271     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1272                                      advances, len);
1274     if (face->overstrike)
1275       {
1276         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1277         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1278                                          advances, len);
1279       }
1281     CGContextRestoreGState (gcontext);
1282   }
1283 #endif  /* NS_IMPL_COCOA */
1285   unblock_input ();
1286   return to-from;
1291 /* ==========================================================================
1293     Font glyph and metrics caching functions
1295    ========================================================================== */
1297 /* Find and cache corresponding glyph codes for unicode values in given
1298    hi-byte block of 256. */
1299 static void
1300 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1302 #ifdef NS_IMPL_COCOA
1303   static EmacsGlyphStorage *glyphStorage;
1304   static char firstTime = 1;
1305 #endif
1306   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1307   unsigned int i, g, idx;
1308   unsigned short *glyphs;
1310   if (NSFONT_TRACE)
1311     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1312             font_info, block);
1314   block_input ();
1316 #ifdef NS_IMPL_COCOA
1317   if (firstTime)
1318     {
1319       firstTime = 0;
1320       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1321     }
1322 #endif
1324   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1325   if (!unichars || !(font_info->glyphs[block]))
1326     emacs_abort ();
1328   /* create a string containing all Unicode characters in this block */
1329   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1330     if (idx < 0xD800 || idx > 0xDFFF)
1331       unichars[i] = idx;
1332     else
1333       unichars[i] = 0xFEFF;
1334   unichars[0x100] = 0;
1336   {
1337 #ifdef NS_IMPL_COCOA
1338     NSString *allChars = [[NSString alloc]
1339                                initWithCharactersNoCopy: unichars
1340                                                  length: 0x100
1341                                            freeWhenDone: NO];
1342     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1343     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1344     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1345     NSUInteger gInd = 0, cInd = 0;
1347     [glyphStorage setString: allChars font: font_info->nsfont];
1348     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1349                         desiredNumberOfCharacters: glyphStorage->maxChar
1350                                        glyphIndex: &gInd characterIndex: &cInd];
1351 #endif
1352     glyphs = font_info->glyphs[block];
1353     for (i = 0; i < 0x100; i++, glyphs++)
1354       {
1355 #ifdef NS_IMPL_GNUSTEP
1356         g = unichars[i];
1357 #else
1358         g = glyphStorage->cglyphs[i];
1359         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1360         if (g > numGlyphs || g == NSNullGlyph)
1361           g = INVALID_GLYPH; /* hopefully unused... */
1362 #endif
1363         *glyphs = g;
1364       }
1366 #ifdef NS_IMPL_COCOA
1367     [allChars release];
1368 #endif
1369   }
1371   unblock_input ();
1372   xfree (unichars);
1376 /* Determine and cache metrics for corresponding glyph codes in given
1377    hi-byte block of 256. */
1378 static void
1379 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1381   unsigned int i, g;
1382   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1383   NSFont *sfont;
1384   struct font_metrics *metrics;
1386   if (NSFONT_TRACE)
1387     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1388             font_info, block);
1390 #ifdef NS_IMPL_GNUSTEP
1391   /* not implemented yet (as of startup 0.18), so punt */
1392   if (numGlyphs == 0)
1393     numGlyphs = 0x10000;
1394 #endif
1396   block_input ();
1397 #ifdef NS_IMPL_COCOA
1398   sfont = [font_info->nsfont screenFontWithRenderingMode:
1399                       NSFontAntialiasedIntegerAdvancementsRenderingMode];
1400 #else
1401   sfont = [font_info->nsfont screenFont];
1402 #endif
1404   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1405   if (!(font_info->metrics[block]))
1406     emacs_abort ();
1408   metrics = font_info->metrics[block];
1409   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1410     {
1411       CGFloat w, lb, rb;
1412       NSRect r = [sfont boundingRectForGlyph: g];
1414       w = max ([sfont advancementForGlyph: g].width, 2.0);
1415       metrics->width = lrint (w);
1417       lb = r.origin.x;
1418       rb = r.size.width - w;
1419       // Add to bearing for LCD smoothing.  We don't know if it is there.
1420       if (lb < 0)
1421         metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1422       if (font_info->ital)
1423         rb += (CGFloat) (0.22F * font_info->height);
1424       metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1426       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1427  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1428       metrics->ascent = r.size.height - metrics->descent;
1429 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1430     }
1431   unblock_input ();
1435 #ifdef NS_IMPL_COCOA
1436 /* helper for font glyph setup */
1437 @implementation EmacsGlyphStorage
1439 - init
1441   return [self initWithCapacity: 1024];
1444 - initWithCapacity: (unsigned long) c
1446   self = [super init];
1447   maxChar = 0;
1448   maxGlyph = 0;
1449   dict = [NSMutableDictionary new];
1450   cglyphs = xmalloc (c * sizeof (CGGlyph));
1451   return self;
1454 - (void) dealloc
1456   if (attrStr != nil)
1457     [attrStr release];
1458   [dict release];
1459   xfree (cglyphs);
1460   [super dealloc];
1463 - (void) setString: (NSString *)str font: (NSFont *)font
1465   [dict setObject: font forKey: NSFontAttributeName];
1466   if (attrStr != nil)
1467     [attrStr release];
1468   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1469   maxChar = [str length];
1470   maxGlyph = 0;
1473 /* NSGlyphStorage protocol */
1474 - (NSUInteger)layoutOptions
1476   return 0;
1479 - (NSAttributedString *)attributedString
1481   return attrStr;
1484 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1485         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1486         characterIndex: (NSUInteger)charIndex
1488   len = glyphIndex+length;
1489   for (i =glyphIndex; i<len; i++)
1490     cglyphs[i] = glyphs[i-glyphIndex];
1491   if (len > maxGlyph)
1492     maxGlyph = len;
1495 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1496         forGlyphAtIndex: (NSUInteger)glyphIndex
1498   return;
1501 @end
1502 #endif /* NS_IMPL_COCOA */
1505 /* Debugging */
1506 void
1507 ns_dump_glyphstring (struct glyph_string *s)
1509   int i;
1511   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1512 "overlap = %d, bg_filled = %d:",
1513            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1514            s->row->overlapping_p, s->background_filled_p);
1515   for (i =0; i<s->nchars; i++)
1516     {
1517       int c = s->first_glyph[i].u.ch;
1518       fprintf (stderr, "%c", c);
1519     }
1520   fprintf (stderr, "\n");
1524 void
1525 syms_of_nsfont (void)
1527   nsfont_driver.type = Qns;
1528   register_font_driver (&nsfont_driver, NULL);
1529   DEFSYM (Qcondensed, "condensed");
1530   DEFSYM (Qexpanded, "expanded");
1531   DEFSYM (Qapple, "apple");
1532   DEFSYM (Qmedium, "medium");
1533   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1534                doc: /* Internal use: maps font registry to Unicode script. */);
1536   ascii_printable = NULL;