Spelling fixes.
[emacs.git] / src / nsfont.m
blob58663804a2fe6a8aed58bfaf9ff08865e9adb8ac
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 "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 extern Lisp_Object Qns;
49 extern Lisp_Object Qnormal, Qbold, Qitalic;
50 static Lisp_Object Qapple, Qroman, Qmedium;
51 static Lisp_Object Qcondensed, Qexpanded;
52 extern Lisp_Object Qappend;
53 extern float ns_antialias_threshold;
56 /* font glyph and metrics caching functions, implemented at end */
57 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
58                               unsigned char block);
59 static void ns_glyph_metrics (struct nsfont_info *font_info,
60                               unsigned char block);
62 #define INVALID_GLYPH 0xFFFF
64 /* ==========================================================================
66     Utilities
68    ========================================================================== */
71 /* Replace spaces w/another character so emacs core font parsing routines
72    aren't thrown off. */
73 static void
74 ns_escape_name (char *name)
76   for (; *name; name++)
77     if (*name == ' ')
78       *name = '_';
82 /* Reconstruct spaces in a font family name passed through emacs. */
83 static void
84 ns_unescape_name (char *name)
86   for (; *name; name++)
87     if (*name == '_')
88       *name = ' ';
92 /* Extract family name from a font spec. */
93 static NSString *
94 ns_get_family (Lisp_Object font_spec)
96   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
97   if (NILP (tem))
98       return nil;
99   else
100     {
101       char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
102       NSString *family;
103       ns_unescape_name (tmp);
104       family = [NSString stringWithUTF8String: tmp];
105       xfree (tmp);
106       return family;
107     }
111 /* Return 0 if attr not set, else value (which might also be 0).
112    On Leopard 0 gets returned even on descriptors where the attribute
113    was never set, so there's no way to distinguish between unspecified
114    and set to not have.  Callers should assume 0 means unspecified. */
115 static float
116 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
118     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
119     NSNumber *val = [tdict objectForKey: trait];
120     return val == nil ? 0.0F : [val floatValue];
124 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
125    to NSFont descriptor.  Information under extra only needed for matching. */
126 #define STYLE_REF 100
127 static NSFontDescriptor *
128 ns_spec_to_descriptor (Lisp_Object font_spec)
130     NSFontDescriptor *fdesc;
131     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
132     NSMutableDictionary *tdict = [NSMutableDictionary new];
133     NSString *family = ns_get_family (font_spec);
134     float n;
136     /* add each attr in font_spec to fdAttrs.. */
137     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
138     if (n != -1 && n != STYLE_REF)
139         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
140                   forKey: NSFontWeightTrait];
141     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
142     if (n != -1 && n != STYLE_REF)
143         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
144                   forKey: NSFontSlantTrait];
145     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
146     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
147         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
148                   forKey: NSFontWidthTrait];
149     if ([tdict count] > 0)
150         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
152     fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
153                retain] autorelease];
155     if (family != nil)
156       {
157         NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
158         fdesc = [[fdesc2 retain] autorelease];
159       }
161     [fdAttrs release];
162     [tdict release];
163     return fdesc;
167 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
168 static Lisp_Object
169 ns_descriptor_to_entity (NSFontDescriptor *desc,
170                          Lisp_Object extra,
171                          const char *style)
173     Lisp_Object font_entity = font_make_entity ();
174     /*   NSString *psName = [desc postscriptName]; */
175     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
176     unsigned int traits = [desc symbolicTraits];
177     char *escapedFamily;
179     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
180     if (family == nil)
181       family = [desc objectForKey: NSFontNameAttribute];
182     if (family == nil)
183       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
185     escapedFamily = xstrdup ([family UTF8String]);
186     ns_escape_name (escapedFamily);
188     ASET (font_entity, FONT_TYPE_INDEX, Qns);
189     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
190     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
191     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
192     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
194     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
195                     traits & NSFontBoldTrait ? Qbold : Qmedium);
196 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
197                     make_number (100 + 100
198                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
199     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
200                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
201 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
202                     make_number (100 + 100
203                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
204     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
205                     traits & NSFontCondensedTrait ? Qcondensed :
206                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
207 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
208                     make_number (100 + 100
209                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
211     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
212     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
213     ASET (font_entity, FONT_SPACING_INDEX,
214           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
215               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
217     ASET (font_entity, FONT_EXTRA_INDEX, extra);
218     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
220     if (NSFONT_TRACE)
221       {
222         fprintf (stderr, "created font_entity:\n    ");
223         debug_print (font_entity);
224       }
226     xfree (escapedFamily);
227     return font_entity;
231 /* Default font entity. */
232 static Lisp_Object
233 ns_fallback_entity (void)
235   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
236       fontDescriptor], Qnil, NULL);
240 /* Utility: get width of a char c in screen font SFONT */
241 static CGFloat
242 ns_char_width (NSFont *sfont, int c)
244   CGFloat w = -1.0;
245   NSString *cstr = [NSString stringWithFormat: @"%c", c];
247 #ifdef NS_IMPL_COCOA
248   NSGlyph glyph = [sfont glyphWithName: cstr];
249   if (glyph)
250     w = [sfont advancementForGlyph: glyph].width;
251 #endif
253   if (w < 0.0)
254     {
255       NSDictionary *attrsDictionary =
256         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
257       w = [cstr sizeWithAttributes: attrsDictionary].width;
258     }
260   return max (w, 1.0);
263 /* Return average width over ASCII printable characters for SFONT.  */
265 static NSString *ascii_printable;
267 static int
268 ns_ascii_average_width (NSFont *sfont)
270   CGFloat w = -1.0;
272   if (!ascii_printable)
273     {
274       char chars[96];
275       int ch;
276       for (ch = 0; ch < 95; ch++)
277         chars[ch] = ' ' + ch;
278       chars[95] = '\0';
280       ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
281     }
283 #ifdef NS_IMPL_COCOA
284   NSGlyph glyph = [sfont glyphWithName: ascii_printable];
285   if (glyph)
286     w = [sfont advancementForGlyph: glyph].width;
287 #endif
289   if (w < (CGFloat) 0.0)
290     {
291       NSDictionary *attrsDictionary =
292         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
293       w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
294     }
296   return lrint (w / (CGFloat) 95.0);
300 /* Return whether set1 covers set2 to a reasonable extent given by pct.
301    We check, out of each 16 Unicode char range containing chars in set2,
302    whether at least one character is present in set1.
303    This must be true for pct of the pairs to consider it covering. */
304 static BOOL
305 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
307     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
308     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
309     int i, off = 0, tot = 0;
311     /* Work around what appears to be a GNUstep bug.
312        See <http://bugs.gnu.org/11853>.  */
313     if (! (bytes1 && bytes2))
314       return NO;
316     for (i=0; i<4096; i++, bytes1++, bytes2++)
317         if (*bytes2)
318           {
319             tot++;
320             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
321                 off++;
322           }
323 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
324     return (float)off / tot < 1.0F - pct;
328 /* Convert :lang property to a script.  Use of :lang property by font backend
329    seems to be limited for now (2009/05) to ja, zh, and ko. */
330 static NSString
331 *ns_lang_to_script (Lisp_Object lang)
333     if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
334         return @"han";
335     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
336              have more characters. */
337     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
338         return @"han";
339     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
340         return @"hangul";
341     else
342         return @"";
346 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
347    everyone just use some standard Unicode names for these?) */
348 static NSString
349 *ns_otf_to_script (Lisp_Object otf)
351     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
352     return CONSP (script)
353         ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
354         : @"";
358 /* Convert a font registry, such as  */
359 static NSString
360 *ns_registry_to_script (char *reg)
362     Lisp_Object script, r, rts = Vns_reg_to_script;
363     while (CONSP (rts))
364       {
365         r = XCAR (XCAR (rts));
366         if (!strncmp (SSDATA (r), reg, SBYTES (r)))
367           {
368             script = XCDR (XCAR (rts));
369             return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
370           }
371         rts = XCDR (rts);
372       }
373     return  @"";
377 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
378    plus registry regular property, for something that can be mapped to a
379    Unicode script.  Empty string returned if no script spec found. */
380 static NSString
381 *ns_get_req_script (Lisp_Object font_spec)
383     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
384     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
386     /* The extra-bundle properties have priority. */
387     for ( ; CONSP (extra); extra = XCDR (extra))
388       {
389         Lisp_Object tmp = XCAR (extra);
390         if (CONSP (tmp))
391           {
392             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
393             if (EQ (key, QCscript) && SYMBOLP (val))
394                 return [NSString stringWithUTF8String:
395                             SSDATA (SYMBOL_NAME (val))];
396             if (EQ (key, QClang) && SYMBOLP (val))
397                 return ns_lang_to_script (val);
398             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
399                 return ns_otf_to_script (val);
400           }
401       }
403     /* If we get here, check the charset portion of the registry. */
404     if (! NILP (reg))
405       {
406         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
407            (which causes box rendering if we don't treat it like iso8858-1)
408            but also for ascii (which causes unnecessary font substitution). */
409 #if 0
410         if (EQ (reg, Qiso10646_1))
411           reg = Qiso8859_1;
412 #endif
413         return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
414       }
416     return @"";
420 /* This small function is static in fontset.c.  If it can be made public for
421    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
422 static void
423 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
425     if (EQ (XCAR (arg), val))
426       {
427         if (CONSP (range))
428           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
429         else
430           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
431       }
435 /* Use the Unicode range information in Vchar_script_table to convert a script
436    name into an NSCharacterSet. */
437 static NSCharacterSet
438 *ns_script_to_charset (NSString *scriptName)
440     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
441     Lisp_Object script = intern ([scriptName UTF8String]);
442     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
444     if (! NILP (Fmemq (script, script_list)))
445       {
446         Lisp_Object ranges, range_list;
448         ranges = list1 (script);
449         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
450                         ranges);
451         range_list = Fnreverse (XCDR (ranges));
452         if (! NILP (range_list))
453           {
454             for (; CONSP (range_list); range_list = XCDR (range_list))
455               {
456                 int start = XINT (XCAR (XCAR (range_list)));
457                 int end = XINT (XCDR (XCAR (range_list)));
458                 if (NSFONT_TRACE)
459                     debug_print (XCAR (range_list));
460                 if (end < 0x10000)
461                     [charset addCharactersInRange:
462                         NSMakeRange (start, end-start)];
463               }
464           }
465       }
466     return charset;
470 /* Return an array of font families containing characters for the given
471    script, for the given coverage criterion, including at least LastResort.
472    Results are cached by script for faster access.
473    If none are found, we reduce the percentage and try again, until 5%.
474    This provides a font with at least some characters if such can be found.
475    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
476    (b) need approximate match as fonts covering full Unicode ranges are rare. */
477 static NSSet
478 *ns_get_covering_families (NSString *script, float pct)
480     static NSMutableDictionary *scriptToFamilies = nil;
481     NSMutableSet *families;
483     if (NSFONT_TRACE)
484         NSLog(@"Request covering families for script: '%@'", script);
486     if (scriptToFamilies == nil)
487         scriptToFamilies = [[NSMutableDictionary alloc] init];
489     if ((families = [scriptToFamilies objectForKey: script]) == nil)
490       {
491         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
492         NSArray *allFamilies = [fontMgr availableFontFamilies];
494         if ([script length] == 0)
495             families = [NSMutableSet setWithArray: allFamilies];
496         else
497           {
498             NSCharacterSet *charset = ns_script_to_charset (script);
499             NSString *family;
500             families = [NSMutableSet setWithCapacity: 10];
501             while (1)
502               {
503                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
504                 while ((family = [allFamiliesEnum nextObject]))
505                   {
506                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
507                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
508                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
509                     if (fset == nil)
510                       fset = [NSCharacterSet characterSetWithRange:
511                                                NSMakeRange (0, 127)];
512                     if (ns_charset_covers(fset, charset, pct))
513                         [families addObject: family];
514                   }
515                 pct -= 0.2F;
516                 if ([families count] > 0 || pct < 0.05F)
517                     break;
518               }
519             [charset release];
520           }
521 #ifdef NS_IMPL_COCOA
522         if ([families count] == 0)
523             [families addObject: @"LastResort"];
524 #endif
525         [scriptToFamilies setObject: families forKey: script];
526       }
528     if (NSFONT_TRACE)
529       NSLog(@"    returning %lu families", (unsigned long)[families count]);
530     return families;
534 /* Implementation for list() and match().  List() can return nil, match()
535 must return something.  Strategy is to drop family name from attribute
536 matching set for match. */
537 static Lisp_Object
538 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
540     Lisp_Object tem, list = Qnil;
541     NSFontDescriptor *fdesc, *desc;
542     NSMutableSet *fkeys;
543     NSArray *matchingDescs;
544     NSEnumerator *dEnum;
545     NSString *family;
546     NSSet *cFamilies;
547     BOOL foundItal = NO;
549     block_input ();
550     if (NSFONT_TRACE)
551       {
552         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
553                  (isMatch ? "match" : "list"));
554         debug_print (font_spec);
555       }
557     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
559     fdesc = ns_spec_to_descriptor (font_spec);
560     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
561     if (isMatch)
562         [fkeys removeObject: NSFontFamilyAttribute];
564     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
566     if (NSFONT_TRACE)
567         NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
568               (unsigned long)[matchingDescs count]);
570     for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
571       {
572         if (![cFamilies containsObject:
573                  [desc objectForKey: NSFontFamilyAttribute]])
574             continue;
575         tem = ns_descriptor_to_entity (desc,
576                                          AREF (font_spec, FONT_EXTRA_INDEX),
577                                        NULL);
578         if (isMatch)
579           return tem;
580         list = Fcons (tem, list);
581         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
582             foundItal = YES;
583       }
585     /* Add synthItal member if needed. */
586     family = [fdesc objectForKey: NSFontFamilyAttribute];
587     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
588       {
589         NSFontDescriptor *s1 = [NSFontDescriptor new];
590         NSFontDescriptor *sDesc
591           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
592               fontDescriptorWithFamily: family];
593         list = Fcons (ns_descriptor_to_entity (sDesc,
594                                          AREF (font_spec, FONT_EXTRA_INDEX),
595                                          "synthItal"), list);
596         [s1 release];
597       }
599     unblock_input ();
601     /* Return something if was a match and nothing found. */
602     if (isMatch)
603       return ns_fallback_entity ();
605     if (NSFONT_TRACE)
606         fprintf (stderr, "    Returning %"pI"d entities.\n",
607                  XINT (Flength (list)));
609     return list;
614 /* ==========================================================================
616     Font driver implementation
618    ========================================================================== */
621 static Lisp_Object nsfont_get_cache (struct frame *frame);
622 static Lisp_Object nsfont_list (struct frame *, Lisp_Object);
623 static Lisp_Object nsfont_match (struct frame *, Lisp_Object);
624 static Lisp_Object nsfont_list_family (struct frame *);
625 static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity,
626                                  int pixel_size);
627 static void nsfont_close (struct font *font);
628 static int nsfont_has_char (Lisp_Object entity, int c);
629 static unsigned int nsfont_encode_char (struct font *font, int c);
630 static int nsfont_text_extents (struct font *font, unsigned int *code,
631                                 int nglyphs, struct font_metrics *metrics);
632 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
633                         bool with_background);
635 struct font_driver nsfont_driver =
636   {
637     0,                          /* Qns */
638     1,                          /* case sensitive */
639     nsfont_get_cache,
640     nsfont_list,
641     nsfont_match,
642     nsfont_list_family,
643     NULL,                       /*free_entity */
644     nsfont_open,
645     nsfont_close,
646     NULL,                       /* prepare_face */
647     NULL,                       /* done_face */
648     nsfont_has_char,
649     nsfont_encode_char,
650     nsfont_text_extents,
651     nsfont_draw,
652     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
653                  anchor_point, otf_capability, otf_driver,
654                  start_for_frame, end_for_frame, shape */
655   };
658 /* Return a cache of font-entities on FRAME.  The cache must be a
659    cons whose cdr part is the actual cache area.  */
660 static Lisp_Object
661 nsfont_get_cache (struct frame *frame)
663   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (frame);
664   return (dpyinfo->name_list_element);
668 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
669    **list** of font-entities.  This and match () are sole APIs that allocate
670    font-entities.  Properties to be considered (2009/05/19) are:
671    regular: foundry, family, adstyle, registry
672    extended: script, lang, otf
673   "Extended" properties are not part of the vector but get stored as
674    lisp properties under FONT_EXTRA_INDEX.
676    The returned entities should have type set (to 'ns), plus the following:
677    foundry, family, adstyle, registry,
678    weight, slant, width, size (0 if scalable),
679    dpi, spacing, avgwidth (0 if scalable)  */
680 static Lisp_Object
681 nsfont_list (struct frame *f, Lisp_Object font_spec)
683   return ns_findfonts (font_spec, NO);
687 /* Return a font entity most closely matching with FONT_SPEC on
688    FRAME.  The closeness is determined by the font backend, thus
689    `face-font-selection-order' is ignored here.
690    Properties to be considered are same as for list(). */
691 static Lisp_Object
692 nsfont_match (struct frame *f, Lisp_Object font_spec)
694   return ns_findfonts (font_spec, YES);
698 /* List available families.  The value is a list of family names
699    (symbols). */
700 static Lisp_Object
701 nsfont_list_family (struct frame *f)
703   Lisp_Object list = Qnil;
704   NSEnumerator *families;
705   NSString *family;
707   block_input ();
708   families = [[[NSFontManager sharedFontManager] availableFontFamilies]
709                objectEnumerator];
710   while ((family = [families nextObject]))
711       list = Fcons (intern ([family UTF8String]), list);
712   /* FIXME: escape the name? */
714   if (NSFONT_TRACE)
715     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
716              XINT (Flength (list)));
718   unblock_input ();
719   return list;
723 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
724    scalable, open it with PIXEL_SIZE.  */
725 static Lisp_Object
726 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
728   BOOL synthItal;
729   unsigned int traits = 0;
730   struct nsfont_info *font_info;
731   struct font *font;
732   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
733   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
734   NSString *family;
735   NSFont *nsfont, *sfont;
736   Lisp_Object tem;
737   NSRect brect;
738   Lisp_Object font_object;
739   int fixLeopardBug;
741   block_input ();
743   if (NSFONT_TRACE)
744     {
745       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
746       debug_print (font_entity);
747     }
749   if (pixel_size <= 0)
750     {
751       /* try to get it out of frame params */
752         Lisp_Object tem = get_frame_param (f, Qfontsize);
753         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
754     }
756   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
757   synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
758                                        9);
759   family = ns_get_family (font_entity);
760   if (family == nil)
761     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
762   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
763      when setting family in ns_spec_to_descriptor(). */
764   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
765       traits |= NSBoldFontMask;
766   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
767       traits |= NSItalicFontMask;
769   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
770   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
771   nsfont = [fontMgr fontWithFamily: family
772                             traits: traits weight: fixLeopardBug
773                               size: pixel_size];
774   /* if didn't find, try synthetic italic */
775   if (nsfont == nil && synthItal)
776     {
777       nsfont = [fontMgr fontWithFamily: family
778                                 traits: traits & ~NSItalicFontMask
779                                 weight: fixLeopardBug size: pixel_size];
780     }
781 #ifdef NS_IMPL_COCOA
782   /* LastResort not really a family */
783   if (nsfont == nil && [@"LastResort" isEqualToString: family])
784       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
785 #endif
787   if (nsfont == nil)
788     {
789       message_with_string ("*** Warning: font in family '%s' not found",
790                           build_string ([family UTF8String]), 1);
791       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
792     }
794   if (NSFONT_TRACE)
795     NSLog (@"%@\n", nsfont);
797   font_object = font_make_object (VECSIZE (struct nsfont_info),
798                                   font_entity, pixel_size);
799   ASET (font_object, FONT_TYPE_INDEX, nsfont_driver.type);
800   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
801   font = (struct font *) font_info;
802   if (!font)
803     {
804       unblock_input ();
805       return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
806     }
808   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
809   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
811   /* for metrics */
812 #ifdef NS_IMPL_COCOA
813   sfont = [nsfont screenFontWithRenderingMode:
814                     NSFontAntialiasedIntegerAdvancementsRenderingMode];
815 #else
816   sfont = [nsfont screenFont];
817 #endif
819   if (sfont == nil)
820     sfont = nsfont;
822   /* non-metric backend font struct fields */
823   font = (struct font *) font_info;
824   font->pixel_size = [sfont pointSize];
825   font->driver = &nsfont_driver;
826   font->encoding_charset = -1;
827   font->repertory_charset = -1;
828   font->default_ascent = 0;
829   font->vertical_centering = 0;
830   font->baseline_offset = 0;
831   font->relative_compose = 0;
832   font->font_encoder = NULL;
834   font->props[FONT_FORMAT_INDEX] = Qns;
835   font->props[FONT_FILE_INDEX] = Qnil;
837   {
838     const char *fontName = [[nsfont fontName] UTF8String];
840     /* The values specified by fonts are not always exact. For
841      * example, a 6x8 font could specify that the descender is
842      * -2.00000405... (represented by 0xc000000220000000).  Without
843      * adjustment, the code below would round the descender to -3,
844      * resulting in a font that would be one pixel higher than
845      * intended. */
846     CGFloat adjusted_descender = [sfont descender] + 0.0001;
848 #ifdef NS_IMPL_GNUSTEP
849     font_info->nsfont = sfont;
850 #else
851     font_info->nsfont = nsfont;
852 #endif
853     [font_info->nsfont retain];
855     /* set up ns_font (defined in nsgui.h) */
856     font_info->name = xstrdup (fontName);
857     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
858     font_info->ital =
859       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
861     /* Metrics etc.; some fonts return an unusually large max advance, so we
862        only use it for fonts that have wide characters. */
863     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
864       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
866     brect =  [sfont boundingRectForFont];
868     font_info->underpos = [sfont underlinePosition];
869     font_info->underwidth = [sfont underlineThickness];
870     font_info->size = font->pixel_size;
872     /* max bounds */
873     font->ascent = font_info->max_bounds.ascent = lrint ([sfont ascender]);
874     /* Descender is usually negative.  Use floor to avoid
875        clipping descenders. */
876     font->descent =
877       font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
878     font_info->height =
879       font_info->max_bounds.ascent + font_info->max_bounds.descent;
880     font_info->max_bounds.width = lrint (font_info->width);
881     font_info->max_bounds.lbearing = lrint (brect.origin.x);
882     font_info->max_bounds.rbearing =
883       lrint (brect.size.width - (CGFloat) font_info->width);
885 #ifdef NS_IMPL_COCOA
886     /* set up synthItal and the CG font */
887     font_info->synthItal = synthItal;
888     {
889       ATSFontRef atsFont = ATSFontFindFromPostScriptName
890         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
892       if (atsFont == kATSFontRefUnspecified)
893         {
894           /* see if we can get it by dropping italic (then synthesizing) */
895           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
896               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
897                 fontName], kATSOptionFlagsDefault);
898           if (atsFont != kATSFontRefUnspecified)
899               font_info->synthItal = YES;
900           else
901             {
902               /* last resort fallback */
903               atsFont = ATSFontFindFromPostScriptName
904                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
905             }
906         }
907       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
908     }
909 #endif
911     /* set up metrics portion of font struct */
912     font->ascent = lrint([sfont ascender]);
913     font->descent = -lrint(floor(adjusted_descender));
914     font->space_width = lrint (ns_char_width (sfont, ' '));
915     font->max_width = lrint (font_info->max_bounds.width);
916     font->min_width = font->space_width;  /* Approximate.  */
917     font->average_width = ns_ascii_average_width (sfont);
919     font->height = lrint (font_info->height);
920     font->underline_position = lrint (font_info->underpos);
921     font->underline_thickness = lrint (font_info->underwidth);
923     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
924     font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
925   }
926   unblock_input ();
928   return font_object;
932 /* Close FONT. */
933 static void
934 nsfont_close (struct font *font)
936   struct nsfont_info *font_info = (struct nsfont_info *) font;
938   /* FIXME: font_info may be NULL due to same failure to detect
939      same font that causes need for cache in nsfont_open.  */
940   if (font_info && font_info->name)
941     {
942       int i;
944       for (i = 0; i < 0x100; i++)
945         {
946           xfree (font_info->glyphs[i]);
947           xfree (font_info->metrics[i]);
948         }
949       [font_info->nsfont release];
950 #ifdef NS_IMPL_COCOA
951       CGFontRelease (font_info->cgfont);
952 #endif
953       xfree (font_info->name);
954       font_info->name = NULL;
955     }
959 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
960    return 1.  If not, return 0.  If a font must be opened to check
961    it, return -1. */
962 static int
963 nsfont_has_char (Lisp_Object entity, int c)
965   return -1;
969 /* Return a glyph code of FONT for character C (Unicode code point).
970    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
971 static unsigned int
972 nsfont_encode_char (struct font *font, int c)
974   struct nsfont_info *font_info = (struct nsfont_info *)font;
975   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
976   unsigned short g;
978   if (c > 0xFFFF)
979     return FONT_INVALID_CODE;
981   /* did we already cache this block? */
982   if (!font_info->glyphs[high])
983     ns_uni_to_glyphs (font_info, high);
985   g = font_info->glyphs[high][low];
986   return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
990 /* Perform the size computation of glyphs of FONT and fill in members
991    of METRICS.  The glyphs are specified by their glyph codes in
992    CODE (length NGLYPHS). */
993 static int
994 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
995                      struct font_metrics *metrics)
997   struct nsfont_info *font_info = (struct nsfont_info *)font;
998   struct font_metrics *pcm;
999   unsigned char high, low;
1000   int totalWidth = 0;
1001   int i;
1003   memset (metrics, 0, sizeof (struct font_metrics));
1005   for (i =0; i<nglyphs; i++)
1006     {
1007       /* get metrics for this glyph, filling cache if need be */
1008       /* TODO: get metrics for whole string from an NSLayoutManager
1009                (if not too slow) */
1010       high = (code[i] & 0xFF00) >> 8;
1011       low = code[i] & 0x00FF;
1012       if (!font_info->metrics[high])
1013         ns_glyph_metrics (font_info, high);
1014       pcm = &(font_info->metrics[high][low]);
1016       if (metrics->lbearing > totalWidth + pcm->lbearing)
1017         metrics->lbearing = totalWidth + pcm->lbearing;
1018       if (metrics->rbearing < totalWidth + pcm->rbearing)
1019         metrics->rbearing = totalWidth + pcm->rbearing;
1020       if (metrics->ascent < pcm->ascent)
1021         metrics->ascent = pcm->ascent;
1022       if (metrics->descent < pcm->descent)
1023         metrics->descent = pcm->descent;
1025       totalWidth += pcm->width;
1026     }
1028   metrics->width = totalWidth;
1030   return totalWidth; /* not specified in doc, but xfont.c does it */
1034 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1035    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND,
1036    fill the background in advance.  It is assured that WITH_BACKGROUND
1037    is false when (FROM > 0 || TO < S->nchars). */
1038 static int
1039 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1040              bool with_background)
1041 /* NOTE: focus and clip must be set
1042      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1044   static unsigned char cbuf[1024];
1045   unsigned char *c = cbuf;
1046 #ifdef NS_IMPL_GNUSTEP
1047   static float advances[1024];
1048   float *adv = advances;
1049 #else
1050   static CGSize advances[1024];
1051   CGSize *adv = advances;
1052 #endif
1053   struct face *face;
1054   NSRect r;
1055   struct nsfont_info *font;
1056   NSColor *col, *bgCol;
1057   unsigned short *t = s->char2b;
1058   int i, len, flags;
1059   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1060   int end = isComposite ? s->cmp_to : s->nchars;
1062   block_input ();
1064   font = (struct nsfont_info *)s->face->font;
1065   if (font == NULL)
1066     font = (struct nsfont_info *)FRAME_FONT (s->f);
1068   /* Select face based on input flags */
1069   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
1070     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
1071      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
1072       NS_DUMPGLYPH_NORMAL));
1074   switch (flags)
1075     {
1076     case NS_DUMPGLYPH_CURSOR:
1077       face = s->face;
1078       break;
1079     case NS_DUMPGLYPH_MOUSEFACE:
1080       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1081       if (!face)
1082         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1083       break;
1084     default:
1085       face = s->face;
1086     }
1088   r.origin.x = s->x;
1089   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1090     r.origin.x += abs (s->face->box_line_width);
1092   r.origin.y = s->y;
1093   r.size.height = FONT_HEIGHT (font);
1095   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1096      NS to render the string, it will come out differently from the individual
1097      character widths added up because of layout processing. */
1098   {
1099     int cwidth, twidth = 0;
1100     int hi, lo;
1101     /* FIXME: composition: no vertical displacement is considered. */
1102     t += s->cmp_from; /* advance into composition */
1103     for (i = s->cmp_from; i < end; i++, t++)
1104       {
1105         hi = (*t & 0xFF00) >> 8;
1106         lo = *t & 0x00FF;
1107         if (isComposite)
1108           {
1109             if (!s->first_glyph->u.cmp.automatic)
1110                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1111             else
1112               {
1113                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1114                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1115                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1116                     cwidth = LGLYPH_WIDTH (glyph);
1117                 else
1118                   {
1119                     cwidth = LGLYPH_WADJUST (glyph);
1120 #ifdef NS_IMPL_GNUSTEP
1121                     *(adv-1) += LGLYPH_XOFF (glyph);
1122 #else
1123                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1124 #endif
1125                   }
1126               }
1127           }
1128         else
1129           {
1130             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1131               ns_glyph_metrics (font, hi);
1132             cwidth = font->metrics[hi][lo].width;
1133           }
1134         twidth += cwidth;
1135 #ifdef NS_IMPL_GNUSTEP
1136         *adv++ = cwidth;
1137         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1138 #else
1139         (*adv++).width = cwidth;
1140 #endif
1141       }
1142     len = adv - advances;
1143     r.size.width = twidth;
1144     *c = 0;
1145   }
1147   /* fill background if requested */
1148   if (with_background && !isComposite)
1149     {
1150       NSRect br = r;
1151       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1152       int mbox_line_width = max (s->face->box_line_width, 0);
1154       if (s->row->full_width_p)
1155         {
1156           if (br.origin.x <= fibw + 1 + mbox_line_width)
1157             {
1158               br.size.width += br.origin.x - mbox_line_width;
1159               br.origin.x = mbox_line_width;
1160             }
1161           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1162                 <= fibw+1)
1163             br.size.width += fibw;
1164         }
1165       if (s->face->box == FACE_NO_BOX)
1166         {
1167           /* expand unboxed top row over internal border */
1168           if (br.origin.y <= fibw + 1 + mbox_line_width)
1169             {
1170               br.size.height += br.origin.y;
1171               br.origin.y = 0;
1172             }
1173         }
1174       else
1175         {
1176           int correction = abs (s->face->box_line_width)+1;
1177           br.origin.y += correction;
1178           br.size.height -= 2*correction;
1179           br.origin.x += correction;
1180           br.size.width -= 2*correction;
1181         }
1183       if (!s->face->stipple)
1184         [(NS_FACE_BACKGROUND (face) != 0
1185           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1186           : FRAME_BACKGROUND_COLOR (s->f)) set];
1187       else
1188         {
1189           struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
1190           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1191         }
1192       NSRectFill (br);
1193     }
1196   /* set up for character rendering */
1197   r.origin.y = s->ybase;
1199   col = (NS_FACE_FOREGROUND (face) != 0
1200          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1201          : FRAME_FOREGROUND_COLOR (s->f));
1203   bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
1204            : (NS_FACE_BACKGROUND (face) != 0
1205               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1206               : FRAME_BACKGROUND_COLOR (s->f)));
1208   /* render under GNUstep using DPS */
1209 #ifdef NS_IMPL_GNUSTEP
1210   {
1211     NSGraphicsContext *context = GSCurrentContext ();
1213     DPSgsave (context);
1214     [font->nsfont set];
1216     /* do erase if "foreground" mode */
1217     if (bgCol != nil)
1218       {
1219         [bgCol set];
1220         DPSmoveto (context, r.origin.x, r.origin.y);
1221 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1222         DPSxshow (context, (const char *) cbuf, advances, len);
1223         DPSstroke (context);
1224         [col set];
1225 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1226       }
1228     [col set];
1230     /* draw with DPSxshow () */
1231     DPSmoveto (context, r.origin.x, r.origin.y);
1232     DPSxshow (context, (const char *) cbuf, advances, len);
1233     DPSstroke (context);
1235     DPSgrestore (context);
1236   }
1238 #else  /* NS_IMPL_COCOA */
1239   {
1240     CGContextRef gcontext =
1241       [[NSGraphicsContext currentContext] graphicsPort];
1242     static CGAffineTransform fliptf;
1243     static BOOL firstTime = YES;
1245     if (firstTime)
1246       {
1247         firstTime = NO;
1248         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1249       }
1251     CGContextSaveGState (gcontext);
1253     // Used to be Fix2X (kATSItalicQDSkew), but Fix2X is deprecated
1254     // and kATSItalicQDSkew is 0.25.
1255     fliptf.c =  font->synthItal ? 0.25 : 0.0;
1257     CGContextSetFont (gcontext, font->cgfont);
1258     CGContextSetFontSize (gcontext, font->size);
1259     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1260       CGContextSetShouldAntialias (gcontext, 0);
1261     else
1262       CGContextSetShouldAntialias (gcontext, 1);
1264     CGContextSetTextMatrix (gcontext, fliptf);
1266     if (bgCol != nil)
1267       {
1268         /* foreground drawing; erase first to avoid overstrike */
1269         [bgCol set];
1270         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1271         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1272         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1273         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1274       }
1276     [col set];
1278     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1279     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1280                                      advances, len);
1282     if (face->overstrike)
1283       {
1284         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1285         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1286                                          advances, len);
1287       }
1289     CGContextRestoreGState (gcontext);
1290   }
1291 #endif  /* NS_IMPL_COCOA */
1293   unblock_input ();
1294   return to-from;
1299 /* ==========================================================================
1301     Font glyph and metrics caching functions
1303    ========================================================================== */
1305 /* Find and cache corresponding glyph codes for unicode values in given
1306    hi-byte block of 256. */
1307 static void
1308 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1310 #ifdef NS_IMPL_COCOA
1311   static EmacsGlyphStorage *glyphStorage;
1312   static char firstTime = 1;
1313 #endif
1314   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1315   unsigned int i, g, idx;
1316   unsigned short *glyphs;
1318   if (NSFONT_TRACE)
1319     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1320             font_info, block);
1322   block_input ();
1324 #ifdef NS_IMPL_COCOA
1325   if (firstTime)
1326     {
1327       firstTime = 0;
1328       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1329     }
1330 #endif
1332   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1333   if (!unichars || !(font_info->glyphs[block]))
1334     emacs_abort ();
1336   /* create a string containing all Unicode characters in this block */
1337   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1338     if (idx < 0xD800 || idx > 0xDFFF)
1339       unichars[i] = idx;
1340     else
1341       unichars[i] = 0xFEFF;
1342   unichars[0x100] = 0;
1344   {
1345 #ifdef NS_IMPL_COCOA
1346     NSString *allChars = [[NSString alloc]
1347                                initWithCharactersNoCopy: unichars
1348                                                  length: 0x100
1349                                            freeWhenDone: NO];
1350     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1351     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1352     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1353     NSUInteger gInd = 0, cInd = 0;
1355     [glyphStorage setString: allChars font: font_info->nsfont];
1356     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1357                         desiredNumberOfCharacters: glyphStorage->maxChar
1358                                        glyphIndex: &gInd characterIndex: &cInd];
1359 #endif
1360     glyphs = font_info->glyphs[block];
1361     for (i = 0; i < 0x100; i++, glyphs++)
1362       {
1363 #ifdef NS_IMPL_GNUSTEP
1364         g = unichars[i];
1365 #else
1366         g = glyphStorage->cglyphs[i];
1367         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1368         if (g > numGlyphs || g == NSNullGlyph)
1369           g = INVALID_GLYPH; /* hopefully unused... */
1370 #endif
1371         *glyphs = g;
1372       }
1374 #ifdef NS_IMPL_COCOA
1375     [allChars release];
1376 #endif
1377   }
1379   unblock_input ();
1380   xfree (unichars);
1384 /* Determine and cache metrics for corresponding glyph codes in given
1385    hi-byte block of 256. */
1386 static void
1387 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1389   unsigned int i, g;
1390   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1391   NSFont *sfont;
1392   struct font_metrics *metrics;
1394   if (NSFONT_TRACE)
1395     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1396             font_info, block);
1398 #ifdef NS_IMPL_GNUSTEP
1399   /* not implemented yet (as of startup 0.18), so punt */
1400   if (numGlyphs == 0)
1401     numGlyphs = 0x10000;
1402 #endif
1404   block_input ();
1405 #ifdef NS_IMPL_COCOA
1406   sfont = [font_info->nsfont screenFontWithRenderingMode:
1407                       NSFontAntialiasedIntegerAdvancementsRenderingMode];
1408 #else
1409   sfont = [font_info->nsfont screenFont];
1410 #endif
1412   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1413   if (!(font_info->metrics[block]))
1414     emacs_abort ();
1416   metrics = font_info->metrics[block];
1417   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1418     {
1419       CGFloat w, lb, rb;
1420       NSRect r = [sfont boundingRectForGlyph: g];
1422       w = max ([sfont advancementForGlyph: g].width, 2.0);
1423       metrics->width = lrint (w);
1425       lb = r.origin.x;
1426       rb = r.size.width - w;
1427       // Add to bearing for LCD smoothing.  We don't know if it is there.
1428       if (lb < 0)
1429         metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1430       if (font_info->ital)
1431         rb += (CGFloat) (0.22F * font_info->height);
1432       metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1434       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1435  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1436       metrics->ascent = r.size.height - metrics->descent;
1437 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1438     }
1439   unblock_input ();
1443 #ifdef NS_IMPL_COCOA
1444 /* helper for font glyph setup */
1445 @implementation EmacsGlyphStorage
1447 - init
1449   return [self initWithCapacity: 1024];
1452 - initWithCapacity: (unsigned long) c
1454   self = [super init];
1455   maxChar = 0;
1456   maxGlyph = 0;
1457   dict = [NSMutableDictionary new];
1458   cglyphs = xmalloc (c * sizeof (CGGlyph));
1459   return self;
1462 - (void) dealloc
1464   if (attrStr != nil)
1465     [attrStr release];
1466   [dict release];
1467   xfree (cglyphs);
1468   [super dealloc];
1471 - (void) setString: (NSString *)str font: (NSFont *)font
1473   [dict setObject: font forKey: NSFontAttributeName];
1474   if (attrStr != nil)
1475     [attrStr release];
1476   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1477   maxChar = [str length];
1478   maxGlyph = 0;
1481 /* NSGlyphStorage protocol */
1482 - (NSUInteger)layoutOptions
1484   return 0;
1487 - (NSAttributedString *)attributedString
1489   return attrStr;
1492 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1493         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1494         characterIndex: (NSUInteger)charIndex
1496   len = glyphIndex+length;
1497   for (i =glyphIndex; i<len; i++) 
1498     cglyphs[i] = glyphs[i-glyphIndex];
1499   if (len > maxGlyph)
1500     maxGlyph = len;
1503 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1504         forGlyphAtIndex: (NSUInteger)glyphIndex
1506   return;
1509 @end
1510 #endif /* NS_IMPL_COCOA */
1513 /* Debugging */
1514 void
1515 ns_dump_glyphstring (struct glyph_string *s)
1517   int i;
1519   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1520 "overlap = %d, bg_filled = %d:",
1521            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1522            s->row->overlapping_p, s->background_filled_p);
1523   for (i =0; i<s->nchars; i++)
1524     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1525   fprintf (stderr, "\n");
1529 void
1530 syms_of_nsfont (void)
1532   nsfont_driver.type = Qns;
1533   register_font_driver (&nsfont_driver, NULL);
1534   DEFSYM (Qcondensed, "condensed");
1535   DEFSYM (Qexpanded, "expanded");
1536   DEFSYM (Qapple, "apple");
1537   DEFSYM (Qroman, "roman");
1538   DEFSYM (Qmedium, "medium");
1539   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1540                doc: /* Internal use: maps font registry to Unicode script. */);
1542   ascii_printable = NULL;