* todo-mode.el: Offer to convert legacy file. Update commentary.
[emacs.git] / src / nsfont.m
blob709f2cb0d8670a86032c71bbc07b9fcd9abebb4b
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006-2013 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
23 /* This should be the first include, as it may set up #defines affecting
24    interpretation of even the system includes. */
25 #include <config.h>
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
31 #include "charset.h"
32 #include "frame.h"
33 #include "window.h"
34 #include "fontset.h"
35 #include "nsterm.h"
36 #include "frame.h"
37 #include "character.h"
38 #include "font.h"
39 #include "termchar.h"
41 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
42 #ifdef NS_IMPL_GNUSTEP
43 #import <AppKit/NSFontDescriptor.h>
44 #endif
46 #define NSFONT_TRACE 0
47 #define LCD_SMOOTHING_MARGIN 2
49 extern Lisp_Object Qns;
50 extern Lisp_Object Qnormal, Qbold, Qitalic;
51 static Lisp_Object Qapple, Qroman, Qmedium;
52 static Lisp_Object Qcondensed, Qexpanded;
53 extern Lisp_Object Qappend;
54 extern float ns_antialias_threshold;
55 extern int ns_tmp_flags;
56 extern struct nsfont_info *ns_tmp_font;
59 /* font glyph and metrics caching functions, implemented at end */
60 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
61                               unsigned char block);
62 static void ns_glyph_metrics (struct nsfont_info *font_info,
63                               unsigned char block);
66 /* ==========================================================================
68     Utilities
70    ========================================================================== */
73 /* Replace spaces w/another character so emacs core font parsing routines
74    aren't thrown off. */
75 static void
76 ns_escape_name (char *name)
78   for (; *name; name++)
79     if (*name == ' ')
80       *name = '_';
84 /* Reconstruct spaces in a font family name passed through emacs. */
85 static void
86 ns_unescape_name (char *name)
88   for (; *name; name++)
89     if (*name == '_')
90       *name = ' ';
94 /* Extract family name from a font spec. */
95 static NSString *
96 ns_get_family (Lisp_Object font_spec)
98   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
99   if (NILP (tem))
100       return nil;
101   else
102     {
103       char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
104       NSString *family;
105       ns_unescape_name (tmp);
106       family = [NSString stringWithUTF8String: tmp];
107       xfree (tmp);
108       return family;
109     }
113 /* Return 0 if attr not set, else value (which might also be 0).
114    On Leopard 0 gets returned even on descriptors where the attribute
115    was never set, so there's no way to distinguish between unspecified
116    and set to not have.  Callers should assume 0 means unspecified. */
117 static float
118 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
120     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
121     NSNumber *val = [tdict objectForKey: trait];
122     return val == nil ? 0.0F : [val floatValue];
126 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
127    to NSFont descriptor.  Information under extra only needed for matching. */
128 #define STYLE_REF 100
129 static NSFontDescriptor *
130 ns_spec_to_descriptor (Lisp_Object font_spec)
132     NSFontDescriptor *fdesc;
133     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
134     NSMutableDictionary *tdict = [NSMutableDictionary new];
135     NSString *family = ns_get_family (font_spec);
136     float n;
138     /* add each attr in font_spec to fdAttrs.. */
139     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
140     if (n != -1 && n != STYLE_REF)
141         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
142                   forKey: NSFontWeightTrait];
143     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
144     if (n != -1 && n != STYLE_REF)
145         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
146                   forKey: NSFontSlantTrait];
147     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
148     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
149         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
150                   forKey: NSFontWidthTrait];
151     if ([tdict count] > 0)
152         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
154     fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
155                retain] autorelease];
157     if (family != nil)
158       {
159         NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
160         fdesc = [[fdesc2 retain] autorelease];
161       }
163     [fdAttrs release];
164     [tdict release];
165     return fdesc;
169 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
170 static Lisp_Object
171 ns_descriptor_to_entity (NSFontDescriptor *desc,
172                          Lisp_Object extra,
173                          const char *style)
175     Lisp_Object font_entity = font_make_entity ();
176     /*   NSString *psName = [desc postscriptName]; */
177     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
178     unsigned int traits = [desc symbolicTraits];
179     char *escapedFamily;
181     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
182     if (family == nil)
183       family = [desc objectForKey: NSFontNameAttribute];
184     if (family == nil)
185       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
187     escapedFamily = xstrdup ([family UTF8String]);
188     ns_escape_name (escapedFamily);
190     ASET (font_entity, FONT_TYPE_INDEX, Qns);
191     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
192     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
193     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
194     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
196     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
197                     traits & NSFontBoldTrait ? Qbold : Qmedium);
198 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
199                     make_number (100 + 100
200                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
201     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
202                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
203 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
204                     make_number (100 + 100
205                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
206     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
207                     traits & NSFontCondensedTrait ? Qcondensed :
208                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
209 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
210                     make_number (100 + 100
211                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
213     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
214     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
215     ASET (font_entity, FONT_SPACING_INDEX,
216           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
217               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
219     ASET (font_entity, FONT_EXTRA_INDEX, extra);
220     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
222     if (NSFONT_TRACE)
223       {
224         fprintf (stderr, "created font_entity:\n    ");
225         debug_print (font_entity);
226       }
228     xfree (escapedFamily);
229     return font_entity;
233 /* Default font entity. */
234 static Lisp_Object
235 ns_fallback_entity (void)
237   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
238       fontDescriptor], Qnil, NULL);
242 /* Utility: get width of a char c in screen font SFONT */
243 static CGFloat
244 ns_char_width (NSFont *sfont, int c)
246   CGFloat w = -1.0;
247   NSString *cstr = [NSString stringWithFormat: @"%c", c];
249 #ifdef NS_IMPL_COCOA
250   NSGlyph glyph = [sfont glyphWithName: cstr];
251   if (glyph)
252     w = [sfont advancementForGlyph: glyph].width;
253 #endif
255   if (w < 0.0)
256     {
257       NSDictionary *attrsDictionary =
258         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
259       w = [cstr sizeWithAttributes: attrsDictionary].width;
260     }
262   return max (w, 1.0);
265 /* Return average width over ASCII printable characters for SFONT.  */
267 static NSString *ascii_printable;
269 static int
270 ns_ascii_average_width (NSFont *sfont)
272   CGFloat w = -1.0;
274   if (!ascii_printable)
275     {
276       char chars[96];
277       int ch;
278       for (ch = 0; ch < 95; ch++)
279         chars[ch] = ' ' + ch;
280       chars[95] = '\0';
282       ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
283     }
285 #ifdef NS_IMPL_COCOA
286   NSGlyph glyph = [sfont glyphWithName: ascii_printable];
287   if (glyph)
288     w = [sfont advancementForGlyph: glyph].width;
289 #endif
291   if (w < (CGFloat) 0.0)
292     {
293       NSDictionary *attrsDictionary =
294         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
295       w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
296     }
298   return lrint (w / (CGFloat) 95.0);
302 /* Return whether set1 covers set2 to a reasonable extent given by pct.
303    We check, out of each 16 Unicode char range containing chars in set2,
304    whether at least one character is present in set1.
305    This must be true for pct of the pairs to consider it covering. */
306 static BOOL
307 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
309     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
310     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
311     int i, off = 0, tot = 0;
313     /* Work around what appears to be a GNUstep bug.
314        See <http://bugs.gnu.org/11853>.  */
315     if (! (bytes1 && bytes2))
316       return NO;
318     for (i=0; i<4096; i++, bytes1++, bytes2++)
319         if (*bytes2)
320           {
321             tot++;
322             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
323                 off++;
324           }
325 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
326     return (float)off / tot < 1.0F - pct;
330 /* Convert :lang property to a script.  Use of :lang property by font backend
331    seems to be limited for now (2009/05) to ja, zh, and ko. */
332 static NSString
333 *ns_lang_to_script (Lisp_Object lang)
335     if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
336         return @"han";
337     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
338              have more characters. */
339     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
340         return @"han";
341     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
342         return @"hangul";
343     else
344         return @"";
348 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
349    everyone just use some standard Unicode names for these?) */
350 static NSString
351 *ns_otf_to_script (Lisp_Object otf)
353     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
354     return CONSP (script)
355         ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
356         : @"";
360 /* Convert a font registry, such as  */
361 static NSString
362 *ns_registry_to_script (char *reg)
364     Lisp_Object script, r, rts = Vns_reg_to_script;
365     while CONSP (rts)
366       {
367         r = XCAR (XCAR (rts));
368         if (!strncmp (SSDATA (r), reg, SBYTES (r)))
369           {
370             script = XCDR (XCAR (rts));
371             return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
372           }
373         rts = XCDR (rts);
374       }
375     return  @"";
379 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
380    plus registry regular property, for something that can be mapped to a
381    Unicode script.  Empty string returned if no script spec found. */
382 static NSString
383 *ns_get_req_script (Lisp_Object font_spec)
385     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
386     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
388     /* The extra-bundle properties have priority. */
389     for ( ; CONSP (extra); extra = XCDR (extra))
390       {
391         Lisp_Object tmp = XCAR (extra);
392         if (CONSP (tmp))
393           {
394             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
395             if (EQ (key, QCscript) && SYMBOLP (val))
396                 return [NSString stringWithUTF8String:
397                             SSDATA (SYMBOL_NAME (val))];
398             if (EQ (key, QClang) && SYMBOLP (val))
399                 return ns_lang_to_script (val);
400             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
401                 return ns_otf_to_script (val);
402           }
403       }
405     /* If we get here, check the charset portion of the registry. */
406     if (! NILP (reg))
407       {
408         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
409            (which causes box rendering if we don't treat it like iso8858-1)
410            but also for ascii (which causes unnecessary font substitution). */
411 #if 0
412         if (EQ (reg, Qiso10646_1))
413           reg = Qiso8859_1;
414 #endif
415         return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
416       }
418     return @"";
422 /* This small function is static in fontset.c.  If it can be made public for
423    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
424 static void
425 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
427     if (EQ (XCAR (arg), val))
428       {
429         if (CONSP (range))
430           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
431         else
432           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
433       }
437 /* Use the Unicode range information in Vchar_script_table to convert a script
438    name into an NSCharacterSet. */
439 static NSCharacterSet
440 *ns_script_to_charset (NSString *scriptName)
442     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
443     Lisp_Object script = intern ([scriptName UTF8String]);
444     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
446     if (! NILP (Fmemq (script, script_list)))
447       {
448         Lisp_Object ranges, range_list;
450         ranges = Fcons (script, Qnil);
451         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
452                         ranges);
453         range_list = Fnreverse (XCDR (ranges));
454         if (! NILP (range_list))
455           {
456             for (; CONSP (range_list); range_list = XCDR (range_list))
457               {
458                 int start = XINT (XCAR (XCAR (range_list)));
459                 int end = XINT (XCDR (XCAR (range_list)));
460                 if (NSFONT_TRACE)
461                     debug_print (XCAR (range_list));
462                 if (end < 0x10000)
463                     [charset addCharactersInRange:
464                         NSMakeRange (start, end-start)];
465               }
466           }
467       }
468     return charset;
472 /* Return an array of font families containing characters for the given
473    script, for the given coverage criterion, including at least LastResort.
474    Results are cached by script for faster access.
475    If none are found, we reduce the percentage and try again, until 5%.
476    This provides a font with at least some characters if such can be found.
477    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
478    (b) need approximate match as fonts covering full Unicode ranges are rare. */
479 static NSSet
480 *ns_get_covering_families (NSString *script, float pct)
482     static NSMutableDictionary *scriptToFamilies = nil;
483     NSMutableSet *families;
485     if (NSFONT_TRACE)
486         NSLog(@"Request covering families for script: '%@'", script);
488     if (scriptToFamilies == nil)
489         scriptToFamilies = [[NSMutableDictionary alloc] init];
491     if ((families = [scriptToFamilies objectForKey: script]) == nil)
492       {
493         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
494         NSArray *allFamilies = [fontMgr availableFontFamilies];
496         if ([script length] == 0)
497             families = [NSMutableSet setWithArray: allFamilies];
498         else
499           {
500             NSCharacterSet *charset = ns_script_to_charset (script);
501             NSString *family;
502             families = [NSMutableSet setWithCapacity: 10];
503             while (1)
504               {
505                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
506                 while ((family = [allFamiliesEnum nextObject]))
507                   {
508                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
509                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
510                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
511                     if (fset == nil)
512                       fset = [NSCharacterSet characterSetWithRange:
513                                                NSMakeRange (0, 127)];
514                     if (ns_charset_covers(fset, charset, pct))
515                         [families addObject: family];
516                   }
517                 pct -= 0.2F;
518                 if ([families count] > 0 || pct < 0.05F)
519                     break;
520               }
521             [charset release];
522           }
523 #ifdef NS_IMPL_COCOA
524         if ([families count] == 0)
525             [families addObject: @"LastResort"];
526 #endif
527         [scriptToFamilies setObject: families forKey: script];
528       }
530     if (NSFONT_TRACE)
531         NSLog(@"    returning %d families", [families count]);
532     return families;
536 /* Implementation for list() and match().  List() can return nil, match()
537 must return something.  Strategy is to drop family name from attribute
538 matching set for match. */
539 static Lisp_Object
540 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
542     Lisp_Object tem, list = Qnil;
543     NSFontDescriptor *fdesc, *desc;
544     NSMutableSet *fkeys;
545     NSArray *matchingDescs;
546     NSEnumerator *dEnum;
547     NSString *family;
548     NSSet *cFamilies;
549     BOOL foundItal = NO;
551     block_input ();
552     if (NSFONT_TRACE)
553       {
554         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
555                  (isMatch ? "match" : "list"));
556         debug_print (font_spec);
557       }
559     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
561     fdesc = ns_spec_to_descriptor (font_spec);
562     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
563     if (isMatch)
564         [fkeys removeObject: NSFontFamilyAttribute];
566     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
568     if (NSFONT_TRACE)
569         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
570               [matchingDescs count]);
572     for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
573       {
574         if (![cFamilies containsObject:
575                  [desc objectForKey: NSFontFamilyAttribute]])
576             continue;
577         tem = ns_descriptor_to_entity (desc,
578                                          AREF (font_spec, FONT_EXTRA_INDEX),
579                                        NULL);
580         if (isMatch)
581           return tem;
582         list = Fcons (tem, list);
583         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
584             foundItal = YES;
585       }
587     /* Add synthItal member if needed. */
588     family = [fdesc objectForKey: NSFontFamilyAttribute];
589     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
590       {
591         NSFontDescriptor *s1 = [NSFontDescriptor new];
592         NSFontDescriptor *sDesc
593           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
594               fontDescriptorWithFamily: family];
595         list = Fcons (ns_descriptor_to_entity (sDesc,
596                                          AREF (font_spec, FONT_EXTRA_INDEX),
597                                          "synthItal"), list);
598         [s1 release];
599       }
601     unblock_input ();
603     /* Return something if was a match and nothing found. */
604     if (isMatch)
605       return ns_fallback_entity ();
607     if (NSFONT_TRACE)
608         fprintf (stderr, "    Returning %"pI"d entities.\n",
609                  XINT (Flength (list)));
611     return list;
616 /* ==========================================================================
618     Font driver implementation
620    ========================================================================== */
623 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
624 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
625 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
626 static Lisp_Object nsfont_list_family (Lisp_Object frame);
627 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
628                                  int pixel_size);
629 static void nsfont_close (FRAME_PTR f, struct font *font);
630 static int nsfont_has_char (Lisp_Object entity, int c);
631 static unsigned int nsfont_encode_char (struct font *font, int c);
632 static int nsfont_text_extents (struct font *font, unsigned int *code,
633                                 int nglyphs, struct font_metrics *metrics);
634 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
635                         bool with_background);
637 struct font_driver nsfont_driver =
638   {
639     0,                          /* Qns */
640     1,                          /* case sensitive */
641     nsfont_get_cache,
642     nsfont_list,
643     nsfont_match,
644     nsfont_list_family,
645     NULL,                       /*free_entity */
646     nsfont_open,
647     nsfont_close,
648     NULL,                       /* prepare_face */
649     NULL,                       /* done_face */
650     nsfont_has_char,
651     nsfont_encode_char,
652     nsfont_text_extents,
653     nsfont_draw,
654     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
655                  anchor_point, otf_capability, otf_driver,
656                  start_for_frame, end_for_frame, shape */
657   };
660 /* Return a cache of font-entities on FRAME.  The cache must be a
661    cons whose cdr part is the actual cache area.  */
662 static Lisp_Object
663 nsfont_get_cache (FRAME_PTR frame)
665   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
666   return (dpyinfo->name_list_element);
670 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
671    **list** of font-entities.  This and match () are sole APIs that allocate
672    font-entities.  Properties to be considered (2009/05/19) are:
673    regular: foundry, family, adstyle, registry
674    extended: script, lang, otf
675   "Extended" properties are not part of the vector but get stored as
676    lisp properties under FONT_EXTRA_INDEX.
678    The returned entities should have type set (to 'ns), plus the following:
679    foundry, family, adstyle, registry,
680    weight, slant, width, size (0 if scalable),
681    dpi, spacing, avgwidth (0 if scalable)  */
682 static Lisp_Object
683 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
685     return ns_findfonts (font_spec, NO);
689 /* Return a font entity most closely matching with FONT_SPEC on
690    FRAME.  The closeness is determined by the font backend, thus
691    `face-font-selection-order' is ignored here.
692    Properties to be considered are same as for list(). */
693 static Lisp_Object
694 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
696     return ns_findfonts(font_spec, YES);
700 /* List available families.  The value is a list of family names
701    (symbols). */
702 static Lisp_Object
703 nsfont_list_family (Lisp_Object frame)
705   Lisp_Object list = Qnil;
706   NSEnumerator *families;
707   NSString *family;
709   block_input ();
710   families = [[[NSFontManager sharedFontManager] availableFontFamilies]
711                objectEnumerator];
712   while ((family = [families nextObject]))
713       list = Fcons (intern ([family UTF8String]), list);
714   /* FIXME: escape the name? */
716   if (NSFONT_TRACE)
717     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
718              XINT (Flength (list)));
720   unblock_input ();
721   return list;
725 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
726    scalable, open it with PIXEL_SIZE.  */
727 static Lisp_Object
728 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
730   BOOL synthItal;
731   unsigned int traits = 0;
732   struct nsfont_info *font_info;
733   struct font *font;
734   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
735   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
736   NSString *family;
737   NSFont *nsfont, *sfont;
738   Lisp_Object tem;
739   NSRect brect;
740   Lisp_Object font_object;
741   int fixLeopardBug;
743   block_input ();
745   if (NSFONT_TRACE)
746     {
747       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
748       debug_print (font_entity);
749     }
751   if (pixel_size <= 0)
752     {
753       /* try to get it out of frame params */
754         Lisp_Object tem = get_frame_param (f, Qfontsize);
755         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
756     }
758   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
759   synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
760                                        9);
761   family = ns_get_family (font_entity);
762   if (family == nil)
763     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
764   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
765      when setting family in ns_spec_to_descriptor(). */
766   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
767       traits |= NSBoldFontMask;
768   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
769       traits |= NSItalicFontMask;
771   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
772   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
773   nsfont = [fontMgr fontWithFamily: family
774                             traits: traits weight: fixLeopardBug
775                               size: pixel_size];
776   /* if didn't find, try synthetic italic */
777   if (nsfont == nil && synthItal)
778     {
779       nsfont = [fontMgr fontWithFamily: family
780                                 traits: traits & ~NSItalicFontMask
781                                 weight: fixLeopardBug size: pixel_size];
782     }
783 #ifdef NS_IMPL_COCOA
784   /* LastResort not really a family */
785   if (nsfont == nil && [@"LastResort" isEqualToString: family])
786       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
787 #endif
789   if (nsfont == nil)
790     {
791       message_with_string ("*** Warning: font in family '%s' not found",
792                           build_string ([family UTF8String]), 1);
793       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
794     }
796   if (NSFONT_TRACE)
797     NSLog (@"%@\n", nsfont);
799   font_object = font_make_object (VECSIZE (struct nsfont_info),
800                                   font_entity, pixel_size);
801   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
802   font = (struct font *) font_info;
803   if (!font)
804     {
805       unblock_input ();
806       return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
807     }
809   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
810   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
812   /* for metrics */
813 #ifdef NS_IMPL_COCOA
814   sfont = [nsfont screenFontWithRenderingMode:
815                     NSFontAntialiasedIntegerAdvancementsRenderingMode];
816 #else
817   sfont = [nsfont screenFont];
818 #endif
820   if (sfont == nil)
821     sfont = nsfont;
823   /* non-metric backend font struct fields */
824   font = (struct font *) font_info;
825   font->pixel_size = [sfont pointSize];
826   font->driver = &nsfont_driver;
827   font->encoding_charset = -1;
828   font->repertory_charset = -1;
829   font->default_ascent = 0;
830   font->vertical_centering = 0;
831   font->baseline_offset = 0;
832   font->relative_compose = 0;
833   font->font_encoder = NULL;
835   font->props[FONT_FORMAT_INDEX] = Qns;
836   font->props[FONT_FILE_INDEX] = Qnil;
838   {
839     const char *fontName = [[nsfont fontName] UTF8String];
841     /* The values specified by fonts are not always exact. For
842      * example, a 6x8 font could specify that the descender is
843      * -2.00000405... (represented by 0xc000000220000000).  Without
844      * adjustment, the code below would round the descender to -3,
845      * resulting in a font that would be one pixel higher than
846      * intended. */
847     CGFloat adjusted_descender = [sfont descender] + 0.0001;
849 #ifdef NS_IMPL_GNUSTEP
850     font_info->nsfont = sfont;
851 #else
852     font_info->nsfont = nsfont;
853 #endif
854     [font_info->nsfont retain];
856     /* set up ns_font (defined in nsgui.h) */
857     font_info->name = xstrdup (fontName);
858     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
859     font_info->ital =
860       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
862     /* Metrics etc.; some fonts return an unusually large max advance, so we
863        only use it for fonts that have wide characters. */
864     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
865       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
867     brect =  [sfont boundingRectForFont];
869     font_info->underpos = [sfont underlinePosition];
870     font_info->underwidth = [sfont underlineThickness];
871     font_info->size = font->pixel_size;
873     /* max bounds */
874     font_info->max_bounds.ascent = lrint ([sfont ascender]);
875     /* Descender is usually negative.  Use floor to avoid
876        clipping descenders. */
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] =
925       make_unibyte_string (font_info->name, strlen (font_info->name));
926   }
927   unblock_input ();
929   return font_object;
933 /* Close FONT on frame F. */
934 static void
935 nsfont_close (FRAME_PTR f, struct font *font)
937   struct nsfont_info *font_info = (struct nsfont_info *)font;
938   int i;
940   /* FIXME: this occurs apparently due to same failure to detect same font
941             that causes need for cache in nsfont_open () */
942   if (!font_info)
943       return;
945   for (i =0; i<0x100; i++)
946     {
947       xfree (font_info->glyphs[i]);
948       xfree (font_info->metrics[i]);
949     }
950   [font_info->nsfont release];
951 #ifdef NS_IMPL_COCOA
952   CGFontRelease (font_info->cgfont);
953 #endif
954   xfree (font_info->name);
955   xfree (font_info);
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 == 0xFFFF ? 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 = ns_tmp_font;
1056   NSColor *col, *bgCol;
1057   unsigned short *t = s->char2b;
1058   int i, len;
1059   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1060   int end = isComposite ? s->cmp_to : s->nchars;
1062   block_input ();
1063   /* Select face based on input flags */
1064   switch (ns_tmp_flags)
1065     {
1066     case NS_DUMPGLYPH_CURSOR:
1067       face = s->face;
1068       break;
1069     case NS_DUMPGLYPH_MOUSEFACE:
1070       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1071       if (!face)
1072         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1073       break;
1074     default:
1075       face = s->face;
1076     }
1078   r.origin.x = s->x;
1079   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1080     r.origin.x += abs (s->face->box_line_width);
1082   r.origin.y = s->y;
1083   r.size.height = FONT_HEIGHT (font);
1085   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1086      NS to render the string, it will come out differently from the individual
1087      character widths added up because of layout processing. */
1088   {
1089     int cwidth, twidth = 0;
1090     int hi, lo;
1091     /* FIXME: composition: no vertical displacement is considered. */
1092     t += s->cmp_from; /* advance into composition */
1093     for (i = s->cmp_from; i < end; i++, t++)
1094       {
1095         hi = (*t & 0xFF00) >> 8;
1096         lo = *t & 0x00FF;
1097         if (isComposite)
1098           {
1099             if (!s->first_glyph->u.cmp.automatic)
1100                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1101             else
1102               {
1103                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1104                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1105                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1106                     cwidth = LGLYPH_WIDTH (glyph);
1107                 else
1108                   {
1109                     cwidth = LGLYPH_WADJUST (glyph);
1110 #ifdef NS_IMPL_GNUSTEP
1111                     *(adv-1) += LGLYPH_XOFF (glyph);
1112 #else
1113                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1114 #endif
1115                   }
1116               }
1117           }
1118         else
1119           {
1120             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1121               ns_glyph_metrics (font, hi);
1122             cwidth = font->metrics[hi][lo].width;
1123           }
1124         twidth += cwidth;
1125 #ifdef NS_IMPL_GNUSTEP
1126         *adv++ = cwidth;
1127         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1128 #else
1129         (*adv++).width = cwidth;
1130 #endif
1131       }
1132     len = adv - advances;
1133     r.size.width = twidth;
1134     *c = 0;
1135   }
1137   /* fill background if requested */
1138   if (with_background && !isComposite)
1139     {
1140       NSRect br = r;
1141       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1142       int mbox_line_width = max (s->face->box_line_width, 0);
1144       if (s->row->full_width_p)
1145         {
1146           if (br.origin.x <= fibw + 1 + mbox_line_width)
1147             {
1148               br.size.width += br.origin.x - mbox_line_width;
1149               br.origin.x = mbox_line_width;
1150             }
1151           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1152                 <= fibw+1)
1153             br.size.width += fibw;
1154         }
1155       if (s->face->box == FACE_NO_BOX)
1156         {
1157           /* expand unboxed top row over internal border */
1158           if (br.origin.y <= fibw + 1 + mbox_line_width)
1159             {
1160               br.size.height += br.origin.y;
1161               br.origin.y = 0;
1162             }
1163         }
1164       else
1165         {
1166           int correction = abs (s->face->box_line_width)+1;
1167           br.origin.y += correction;
1168           br.size.height -= 2*correction;
1169           br.origin.x += correction;
1170           br.size.width -= 2*correction;
1171         }
1173       if (!s->face->stipple)
1174         [(NS_FACE_BACKGROUND (face) != 0
1175           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1176           : FRAME_BACKGROUND_COLOR (s->f)) set];
1177       else
1178         {
1179           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1180           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1181         }
1182       NSRectFill (br);
1183     }
1186   /* set up for character rendering */
1187   r.origin.y = s->ybase;
1189   col = (NS_FACE_FOREGROUND (face) != 0
1190          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1191          : FRAME_FOREGROUND_COLOR (s->f));
1192   /* FIXME: find another way to pass this */
1193   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1194            : (NS_FACE_BACKGROUND (face) != 0
1195               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1196               : FRAME_BACKGROUND_COLOR (s->f)));
1198   /* render under GNUstep using DPS */
1199 #ifdef NS_IMPL_GNUSTEP
1200   {
1201     NSGraphicsContext *context = GSCurrentContext ();
1203     DPSgsave (context);
1204     [font->nsfont set];
1206     /* do erase if "foreground" mode */
1207     if (bgCol != nil)
1208       {
1209         [bgCol set];
1210         DPSmoveto (context, r.origin.x, r.origin.y);
1211 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1212         DPSxshow (context, (const char *) cbuf, advances, len);
1213         DPSstroke (context);
1214         [col set];
1215 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1216       }
1218     [col set];
1220     /* draw with DPSxshow () */
1221     DPSmoveto (context, r.origin.x, r.origin.y);
1222     DPSxshow (context, (const char *) cbuf, advances, len);
1223     DPSstroke (context);
1225     DPSgrestore (context);
1226   }
1228 #else  /* NS_IMPL_COCOA */
1229   {
1230     CGContextRef gcontext =
1231       [[NSGraphicsContext currentContext] graphicsPort];
1232     static CGAffineTransform fliptf;
1233     static BOOL firstTime = YES;
1235     if (firstTime)
1236       {
1237         firstTime = NO;
1238         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1239       }
1241     CGContextSaveGState (gcontext);
1243     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1245     CGContextSetFont (gcontext, font->cgfont);
1246     CGContextSetFontSize (gcontext, font->size);
1247     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1248       CGContextSetShouldAntialias (gcontext, 0);
1249     else
1250       CGContextSetShouldAntialias (gcontext, 1);
1252     CGContextSetTextMatrix (gcontext, fliptf);
1254     if (bgCol != nil)
1255       {
1256         /* foreground drawing; erase first to avoid overstrike */
1257         [bgCol set];
1258         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1259         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1260         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1261         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1262       }
1264     [col set];
1266     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1267     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1268                                     advances, len);
1270     if (face->overstrike)
1271       {
1272         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1273         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1274                                         advances, len);
1275       }
1277     CGContextRestoreGState (gcontext);
1278   }
1279 #endif  /* NS_IMPL_COCOA */
1281   /* Draw underline, overline, strike-through. */
1282   ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1284   unblock_input ();
1285   return to-from;
1290 /* ==========================================================================
1292     Font glyph and metrics caching functions
1294    ========================================================================== */
1296 /* Find and cache corresponding glyph codes for unicode values in given
1297    hi-byte block of 256. */
1298 static void
1299 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1301 #ifdef NS_IMPL_COCOA
1302   static EmacsGlyphStorage *glyphStorage;
1303   static char firstTime = 1;
1304 #endif
1305   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1306   unsigned int i, g, idx;
1307   unsigned short *glyphs;
1309   if (NSFONT_TRACE)
1310     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1311             font_info, block);
1313   block_input ();
1315 #ifdef NS_IMPL_COCOA
1316   if (firstTime)
1317     {
1318       firstTime = 0;
1319       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1320     }
1321 #endif
1323   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1324   if (!unichars || !(font_info->glyphs[block]))
1325     emacs_abort ();
1327   /* create a string containing all Unicode characters in this block */
1328   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1329     if (idx < 0xD800 || idx > 0xDFFF)
1330       unichars[i] = idx;
1331     else
1332       unichars[i] = 0xFEFF;
1333   unichars[0x100] = 0;
1335   {
1336 #ifdef NS_IMPL_COCOA
1337     NSString *allChars = [[NSString alloc]
1338                                initWithCharactersNoCopy: unichars
1339                                                  length: 0x100
1340                                            freeWhenDone: NO];
1341     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1342     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1343     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1344     NSUInteger gInd = 0, cInd = 0;
1346     [glyphStorage setString: allChars font: font_info->nsfont];
1347     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1348                         desiredNumberOfCharacters: glyphStorage->maxChar
1349                                        glyphIndex: &gInd characterIndex: &cInd];
1350 #endif
1351     glyphs = font_info->glyphs[block];
1352     for (i = 0; i < 0x100; i++, glyphs++)
1353       {
1354 #ifdef NS_IMPL_GNUSTEP
1355         g = unichars[i];
1356 #else
1357         g = glyphStorage->cglyphs[i];
1358         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1359         if (g > numGlyphs)
1360           g = 0xFFFF; /* hopefully unused... */
1361 #endif
1362         *glyphs = g;
1363       }
1365 #ifdef NS_IMPL_COCOA
1366     [allChars release];
1367 #endif
1368   }
1370   unblock_input ();
1371   xfree (unichars);
1375 /* Determine and cache metrics for corresponding glyph codes in given
1376    hi-byte block of 256. */
1377 static void
1378 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1380   unsigned int i, g;
1381   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1382   NSFont *sfont;
1383   struct font_metrics *metrics;
1385   if (NSFONT_TRACE)
1386     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1387             font_info, block);
1389 #ifdef NS_IMPL_GNUSTEP
1390   /* not implemented yet (as of startup 0.18), so punt */
1391   if (numGlyphs == 0)
1392     numGlyphs = 0x10000;
1393 #endif
1395   block_input ();
1396 #ifdef NS_IMPL_COCOA
1397   sfont = [font_info->nsfont screenFontWithRenderingMode:
1398                       NSFontAntialiasedIntegerAdvancementsRenderingMode];
1399 #else
1400   sfont = [font_info->nsfont screenFont];
1401 #endif
1403   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1404   if (!(font_info->metrics[block]))
1405     emacs_abort ();
1407   metrics = font_info->metrics[block];
1408   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1409     {
1410       CGFloat w, lb, rb;
1411       NSRect r = [sfont boundingRectForGlyph: g];
1413       w = max ([sfont advancementForGlyph: g].width, 2.0);
1414       metrics->width = lrint (w);
1416       lb = r.origin.x;
1417       rb = r.size.width - w;
1418       // Add to bearing for LCD smoothing.  We don't know if it is there.
1419       if (lb < 0)
1420         metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1421       if (font_info->ital)
1422         rb += (CGFloat) (0.22F * font_info->height);
1423       metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1425       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1426  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1427       metrics->ascent = r.size.height - metrics->descent;
1428 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1429     }
1430   unblock_input ();
1434 #ifdef NS_IMPL_COCOA
1435 /* helper for font glyph setup */
1436 @implementation EmacsGlyphStorage
1438 - init
1440   return [self initWithCapacity: 1024];
1443 - initWithCapacity: (unsigned long) c
1445   self = [super init];
1446   maxChar = 0;
1447   maxGlyph = 0;
1448   dict = [NSMutableDictionary new];
1449   cglyphs = xmalloc (c * sizeof (CGGlyph));
1450   return self;
1453 - (void) dealloc
1455   if (attrStr != nil)
1456     [attrStr release];
1457   [dict release];
1458   xfree (cglyphs);
1459   [super dealloc];
1462 - (void) setString: (NSString *)str font: (NSFont *)font
1464   [dict setObject: font forKey: NSFontAttributeName];
1465   if (attrStr != nil)
1466     [attrStr release];
1467   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1468   maxChar = [str length];
1469   maxGlyph = 0;
1472 /* NSGlyphStorage protocol */
1473 - (NSUInteger)layoutOptions
1475   return 0;
1478 - (NSAttributedString *)attributedString
1480   return attrStr;
1483 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1484         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1485         characterIndex: (NSUInteger)charIndex
1487   len = glyphIndex+length;
1488   for (i =glyphIndex; i<len; i++)
1489     cglyphs[i] = glyphs[i-glyphIndex];
1490   if (len > maxGlyph)
1491     maxGlyph = len;
1494 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1495         forGlyphAtIndex: (NSUInteger)glyphIndex
1497   return;
1500 @end
1501 #endif /* NS_IMPL_COCOA */
1504 /* Debugging */
1505 void
1506 ns_dump_glyphstring (struct glyph_string *s)
1508   int i;
1510   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1511 "overlap = %d, bg_filled = %d:",
1512            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1513            s->row->overlapping_p, s->background_filled_p);
1514   for (i =0; i<s->nchars; i++)
1515     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1516   fprintf (stderr, "\n");
1520 void
1521 syms_of_nsfont (void)
1523   nsfont_driver.type = Qns;
1524   register_font_driver (&nsfont_driver, NULL);
1525   DEFSYM (Qcondensed, "condensed");
1526   DEFSYM (Qexpanded, "expanded");
1527   DEFSYM (Qapple, "apple");
1528   DEFSYM (Qroman, "roman");
1529   DEFSYM (Qmedium, "medium");
1530   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1531                doc: /* Internal use: maps font registry to Unicode script. */);
1533   ascii_printable = NULL;