Add a note how to use `tramp-own-remote-path'
[emacs.git] / src / nsfont.m
blob569a69f9fe8515619ea576d0c4fb9ebecc9db8cd
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006-2016 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
23 /* This should be the first include, as it may set up #defines affecting
24    interpretation of even the system includes. */
25 #include <config.h>
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
31 #include "charset.h"
32 #include "frame.h"
33 #include "window.h"
34 #include "fontset.h"
35 #include "nsterm.h"
36 #include "character.h"
37 #include "font.h"
38 #include "termchar.h"
40 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
41 #ifdef NS_IMPL_GNUSTEP
42 #import <AppKit/NSFontDescriptor.h>
43 #endif
45 #define NSFONT_TRACE 0
46 #define LCD_SMOOTHING_MARGIN 2
48 extern float ns_antialias_threshold;
51 /* font glyph and metrics caching functions, implemented at end */
52 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
53                               unsigned char block);
54 static void ns_glyph_metrics (struct nsfont_info *font_info,
55                               unsigned char block);
57 #define INVALID_GLYPH 0xFFFF
59 /* ==========================================================================
61     Utilities
63    ========================================================================== */
66 /* Replace spaces w/another character so emacs core font parsing routines
67    aren't thrown off. */
68 static void
69 ns_escape_name (char *name)
71   for (; *name; name++)
72     if (*name == ' ')
73       *name = '_';
77 /* Reconstruct spaces in a font family name passed through emacs. */
78 static void
79 ns_unescape_name (char *name)
81   for (; *name; name++)
82     if (*name == '_')
83       *name = ' ';
87 /* Extract family name from a font spec. */
88 static NSString *
89 ns_get_family (Lisp_Object font_spec)
91   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
92   if (NILP (tem))
93       return nil;
94   else
95     {
96       char *tmp = xlispstrdup (SYMBOL_NAME (tem));
97       NSString *family;
98       ns_unescape_name (tmp);
99       family = [NSString stringWithUTF8String: tmp];
100       xfree (tmp);
101       return family;
102     }
106 /* Return 0 if attr not set, else value (which might also be 0).
107    On Leopard 0 gets returned even on descriptors where the attribute
108    was never set, so there's no way to distinguish between unspecified
109    and set to not have.  Callers should assume 0 means unspecified. */
110 static float
111 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
113     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
114     NSNumber *val = [tdict objectForKey: trait];
115     return val == nil ? 0.0F : [val floatValue];
119 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
120    to NSFont descriptor.  Information under extra only needed for matching. */
121 #define STYLE_REF 100
122 static NSFontDescriptor *
123 ns_spec_to_descriptor (Lisp_Object font_spec)
125     NSFontDescriptor *fdesc;
126     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
127     NSMutableDictionary *tdict = [NSMutableDictionary new];
128     NSString *family = ns_get_family (font_spec);
129     float n;
131     /* add each attr in font_spec to fdAttrs.. */
132     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
133     if (n != -1 && n != STYLE_REF)
134         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
135                   forKey: NSFontWeightTrait];
136     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
137     if (n != -1 && n != STYLE_REF)
138         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
139                   forKey: NSFontSlantTrait];
140     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
141     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
142         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
143                   forKey: NSFontWidthTrait];
144     if ([tdict count] > 0)
145         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
147     fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
148                retain] autorelease];
150     if (family != nil)
151       {
152         NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
153         fdesc = [[fdesc2 retain] autorelease];
154       }
156     [fdAttrs release];
157     [tdict release];
158     return fdesc;
162 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
163 static Lisp_Object
164 ns_descriptor_to_entity (NSFontDescriptor *desc,
165                          Lisp_Object extra,
166                          const char *style)
168     Lisp_Object font_entity = font_make_entity ();
169     /*   NSString *psName = [desc postscriptName]; */
170     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
171     unsigned int traits = [desc symbolicTraits];
172     char *escapedFamily;
174     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
175     if (family == nil)
176       family = [desc objectForKey: NSFontNameAttribute];
177     if (family == nil)
178       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
180     escapedFamily = xstrdup ([family UTF8String]);
181     ns_escape_name (escapedFamily);
183     ASET (font_entity, FONT_TYPE_INDEX, Qns);
184     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
185     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
186     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
187     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
189     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
190                     traits & NSFontBoldTrait ? Qbold : Qmedium);
191 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
192                     make_number (100 + 100
193                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
194     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
195                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
196 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
197                     make_number (100 + 100
198                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
199     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
200                     traits & NSFontCondensedTrait ? Qcondensed :
201                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
202 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
203                     make_number (100 + 100
204                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
206     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
207     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
208     ASET (font_entity, FONT_SPACING_INDEX,
209           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
210               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
212     ASET (font_entity, FONT_EXTRA_INDEX, extra);
213     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
215     if (NSFONT_TRACE)
216       {
217         fprintf (stderr, "created font_entity:\n    ");
218         debug_print (font_entity);
219       }
221     xfree (escapedFamily);
222     return font_entity;
226 /* Default font entity. */
227 static Lisp_Object
228 ns_fallback_entity (void)
230   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
231       fontDescriptor], Qnil, NULL);
235 /* Utility: get width of a char c in screen font SFONT */
236 static CGFloat
237 ns_char_width (NSFont *sfont, int c)
239   CGFloat w = -1.0;
240   NSString *cstr = [NSString stringWithFormat: @"%c", c];
242 #ifdef NS_IMPL_COCOA
243   NSGlyph glyph = [sfont glyphWithName: cstr];
244   if (glyph)
245     w = [sfont advancementForGlyph: glyph].width;
246 #endif
248   if (w < 0.0)
249     {
250       NSDictionary *attrsDictionary =
251         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
252       w = [cstr sizeWithAttributes: attrsDictionary].width;
253     }
255   return max (w, 1.0);
258 /* Return average width over ASCII printable characters for SFONT.  */
260 static NSString *ascii_printable;
262 static int
263 ns_ascii_average_width (NSFont *sfont)
265   CGFloat w = -1.0;
267   if (!ascii_printable)
268     {
269       char chars[96];
270       int ch;
271       for (ch = 0; ch < 95; ch++)
272         chars[ch] = ' ' + ch;
273       chars[95] = '\0';
275       ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
276     }
278 #ifdef NS_IMPL_COCOA
279   NSGlyph glyph = [sfont glyphWithName: ascii_printable];
280   if (glyph)
281     w = [sfont advancementForGlyph: glyph].width;
282 #endif
284   if (w < (CGFloat) 0.0)
285     {
286       NSDictionary *attrsDictionary =
287         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
288       w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
289     }
291   return lrint (w / (CGFloat) 95.0);
295 /* Return whether set1 covers set2 to a reasonable extent given by pct.
296    We check, out of each 16 Unicode char range containing chars in set2,
297    whether at least one character is present in set1.
298    This must be true for pct of the pairs to consider it covering. */
299 static BOOL
300 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
302     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
303     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
304     int i, off = 0, tot = 0;
306     /* Work around what appears to be a GNUstep bug.
307        See <http://bugs.gnu.org/11853>.  */
308     if (! (bytes1 && bytes2))
309       return NO;
311     for (i=0; i<4096; i++, bytes1++, bytes2++)
312         if (*bytes2)
313           {
314             tot++;
315             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
316                 off++;
317           }
318 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
319     return (float)off / tot < 1.0F - pct;
323 /* Convert :lang property to a script.  Use of :lang property by font backend
324    seems to be limited for now (2009/05) to ja, zh, and ko. */
325 static NSString
326 *ns_lang_to_script (Lisp_Object lang)
328     if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
329         return @"han";
330     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
331              have more characters. */
332     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
333         return @"han";
334     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
335         return @"hangul";
336     else
337         return @"";
341 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
342    everyone just use some standard Unicode names for these?) */
343 static NSString
344 *ns_otf_to_script (Lisp_Object otf)
346     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
347     return CONSP (script)
348         ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
349         : @"";
353 /* Convert a font registry, such as  */
354 static NSString
355 *ns_registry_to_script (char *reg)
357     Lisp_Object script, r, rts = Vns_reg_to_script;
358     while (CONSP (rts))
359       {
360         r = XCAR (XCAR (rts));
361         if (!strncmp (SSDATA (r), reg, SBYTES (r)))
362           {
363             script = XCDR (XCAR (rts));
364             return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
365           }
366         rts = XCDR (rts);
367       }
368     return  @"";
372 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
373    plus registry regular property, for something that can be mapped to a
374    Unicode script.  Empty string returned if no script spec found. */
375 static NSString
376 *ns_get_req_script (Lisp_Object font_spec)
378     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
379     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
381     /* The extra-bundle properties have priority. */
382     for ( ; CONSP (extra); extra = XCDR (extra))
383       {
384         Lisp_Object tmp = XCAR (extra);
385         if (CONSP (tmp))
386           {
387             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
388             if (EQ (key, QCscript) && SYMBOLP (val))
389                 return [NSString stringWithUTF8String:
390                             SSDATA (SYMBOL_NAME (val))];
391             if (EQ (key, QClang) && SYMBOLP (val))
392                 return ns_lang_to_script (val);
393             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
394                 return ns_otf_to_script (val);
395           }
396       }
398     /* If we get here, check the charset portion of the registry. */
399     if (! NILP (reg))
400       {
401         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
402            (which causes box rendering if we don't treat it like iso8858-1)
403            but also for ascii (which causes unnecessary font substitution). */
404 #if 0
405         if (EQ (reg, Qiso10646_1))
406           reg = Qiso8859_1;
407 #endif
408         return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
409       }
411     return @"";
415 /* This small function is static in fontset.c.  If it can be made public for
416    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
417 static void
418 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
420     if (EQ (XCAR (arg), val))
421       {
422         if (CONSP (range))
423           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
424         else
425           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
426       }
430 /* Use the Unicode range information in Vchar_script_table to convert a script
431    name into an NSCharacterSet. */
432 static NSCharacterSet
433 *ns_script_to_charset (NSString *scriptName)
435     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
436     Lisp_Object script = intern ([scriptName UTF8String]);
437     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
439     if (! NILP (Fmemq (script, script_list)))
440       {
441         Lisp_Object ranges, range_list;
443         ranges = list1 (script);
444         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
445                         ranges);
446         range_list = Fnreverse (XCDR (ranges));
447         if (! NILP (range_list))
448           {
449             for (; CONSP (range_list); range_list = XCDR (range_list))
450               {
451                 int start = XINT (XCAR (XCAR (range_list)));
452                 int end = XINT (XCDR (XCAR (range_list)));
453                 if (NSFONT_TRACE)
454                     debug_print (XCAR (range_list));
455                 if (end < 0x10000)
456                     [charset addCharactersInRange:
457                         NSMakeRange (start, end-start)];
458               }
459           }
460       }
461     return charset;
465 /* Return an array of font families containing characters for the given
466    script, for the given coverage criterion, including at least LastResort.
467    Results are cached by script for faster access.
468    If none are found, we reduce the percentage and try again, until 5%.
469    This provides a font with at least some characters if such can be found.
470    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
471    (b) need approximate match as fonts covering full Unicode ranges are rare. */
472 static NSSet
473 *ns_get_covering_families (NSString *script, float pct)
475     static NSMutableDictionary *scriptToFamilies = nil;
476     NSMutableSet *families;
478     if (NSFONT_TRACE)
479         NSLog(@"Request covering families for script: '%@'", script);
481     if (scriptToFamilies == nil)
482         scriptToFamilies = [[NSMutableDictionary alloc] init];
484     if ((families = [scriptToFamilies objectForKey: script]) == nil)
485       {
486         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
487         NSArray *allFamilies = [fontMgr availableFontFamilies];
489         if ([script length] == 0)
490             families = [NSMutableSet setWithArray: allFamilies];
491         else
492           {
493             NSCharacterSet *charset = ns_script_to_charset (script);
494             NSString *family;
495             families = [NSMutableSet setWithCapacity: 10];
496             while (1)
497               {
498                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
499                 while ((family = [allFamiliesEnum nextObject]))
500                   {
501                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
502                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
503                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
504                     if (fset == nil)
505                       fset = [NSCharacterSet characterSetWithRange:
506                                                NSMakeRange (0, 127)];
507                     if (ns_charset_covers(fset, charset, pct))
508                         [families addObject: family];
509                   }
510                 pct -= 0.2F;
511                 if ([families count] > 0 || pct < 0.05F)
512                     break;
513               }
514             [charset release];
515           }
516 #ifdef NS_IMPL_COCOA
517         if ([families count] == 0)
518             [families addObject: @"LastResort"];
519 #endif
520         [scriptToFamilies setObject: families forKey: script];
521       }
523     if (NSFONT_TRACE)
524       NSLog(@"    returning %lu families", (unsigned long)[families count]);
525     return families;
529 /* Implementation for list() and match().  List() can return nil, match()
530 must return something.  Strategy is to drop family name from attribute
531 matching set for match. */
532 static Lisp_Object
533 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
535     Lisp_Object tem, list = Qnil;
536     NSFontDescriptor *fdesc, *desc;
537     NSMutableSet *fkeys;
538     NSArray *matchingDescs;
539     NSEnumerator *dEnum;
540     NSString *family;
541     NSSet *cFamilies;
542     BOOL foundItal = NO;
544     block_input ();
545     if (NSFONT_TRACE)
546       {
547         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
548                  (isMatch ? "match" : "list"));
549         debug_print (font_spec);
550       }
552     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
554     fdesc = ns_spec_to_descriptor (font_spec);
555     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
556     if (isMatch)
557         [fkeys removeObject: NSFontFamilyAttribute];
559     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
561     if (NSFONT_TRACE)
562         NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
563               (unsigned long)[matchingDescs count]);
565     for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
566       {
567         if (![cFamilies containsObject:
568                  [desc objectForKey: NSFontFamilyAttribute]])
569             continue;
570         tem = ns_descriptor_to_entity (desc,
571                                          AREF (font_spec, FONT_EXTRA_INDEX),
572                                        NULL);
573         if (isMatch)
574           return tem;
575         list = Fcons (tem, list);
576         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
577             foundItal = YES;
578       }
580     /* Add synthItal member if needed. */
581     family = [fdesc objectForKey: NSFontFamilyAttribute];
582     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
583       {
584         NSFontDescriptor *s1 = [NSFontDescriptor new];
585         NSFontDescriptor *sDesc
586           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
587               fontDescriptorWithFamily: family];
588         list = Fcons (ns_descriptor_to_entity (sDesc,
589                                          AREF (font_spec, FONT_EXTRA_INDEX),
590                                          "synthItal"), list);
591         [s1 release];
592       }
594     unblock_input ();
596     /* Return something if was a match and nothing found. */
597     if (isMatch)
598       return ns_fallback_entity ();
600     if (NSFONT_TRACE)
601         fprintf (stderr, "    Returning %"pI"d entities.\n",
602                  XINT (Flength (list)));
604     return list;
609 /* ==========================================================================
611     Font driver implementation
613    ========================================================================== */
616 static Lisp_Object nsfont_get_cache (struct frame *frame);
617 static Lisp_Object nsfont_list (struct frame *, Lisp_Object);
618 static Lisp_Object nsfont_match (struct frame *, Lisp_Object);
619 static Lisp_Object nsfont_list_family (struct frame *);
620 static Lisp_Object nsfont_open (struct frame *f, Lisp_Object font_entity,
621                                  int pixel_size);
622 static void nsfont_close (struct font *font);
623 static int nsfont_has_char (Lisp_Object entity, int c);
624 static unsigned int nsfont_encode_char (struct font *font, int c);
625 static void nsfont_text_extents (struct font *font, unsigned int *code,
626                                  int nglyphs, struct font_metrics *metrics);
627 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
628                         bool with_background);
630 struct font_driver nsfont_driver =
631   {
632     0,                          /* Qns */
633     1,                          /* case sensitive */
634     nsfont_get_cache,
635     nsfont_list,
636     nsfont_match,
637     nsfont_list_family,
638     NULL,                       /*free_entity */
639     nsfont_open,
640     nsfont_close,
641     NULL,                       /* prepare_face */
642     NULL,                       /* done_face */
643     nsfont_has_char,
644     nsfont_encode_char,
645     nsfont_text_extents,
646     nsfont_draw,
647     /* excluded: get_bitmap, free_bitmap,
648                  anchor_point, otf_capability, otf_driver,
649                  start_for_frame, end_for_frame, shape */
650   };
653 /* Return a cache of font-entities on FRAME.  The cache must be a
654    cons whose cdr part is the actual cache area.  */
655 static Lisp_Object
656 nsfont_get_cache (struct frame *frame)
658   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (frame);
659   return (dpyinfo->name_list_element);
663 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
664    **list** of font-entities.  This and match () are sole APIs that allocate
665    font-entities.  Properties to be considered (2009/05/19) are:
666    regular: foundry, family, adstyle, registry
667    extended: script, lang, otf
668   "Extended" properties are not part of the vector but get stored as
669    lisp properties under FONT_EXTRA_INDEX.
671    The returned entities should have type set (to 'ns), plus the following:
672    foundry, family, adstyle, registry,
673    weight, slant, width, size (0 if scalable),
674    dpi, spacing, avgwidth (0 if scalable)  */
675 static Lisp_Object
676 nsfont_list (struct frame *f, Lisp_Object font_spec)
678   return ns_findfonts (font_spec, NO);
682 /* Return a font entity most closely matching with FONT_SPEC on
683    FRAME.  The closeness is determined by the font backend, thus
684    `face-font-selection-order' is ignored here.
685    Properties to be considered are same as for list(). */
686 static Lisp_Object
687 nsfont_match (struct frame *f, Lisp_Object font_spec)
689   return ns_findfonts (font_spec, YES);
693 /* List available families.  The value is a list of family names
694    (symbols). */
695 static Lisp_Object
696 nsfont_list_family (struct frame *f)
698   Lisp_Object list = Qnil;
699   NSEnumerator *families;
700   NSString *family;
702   block_input ();
703   families = [[[NSFontManager sharedFontManager] availableFontFamilies]
704                objectEnumerator];
705   while ((family = [families nextObject]))
706       list = Fcons (intern ([family UTF8String]), list);
707   /* FIXME: escape the name? */
709   if (NSFONT_TRACE)
710     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
711              XINT (Flength (list)));
713   unblock_input ();
714   return list;
718 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
719    scalable, open it with PIXEL_SIZE.  */
720 static Lisp_Object
721 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
723   BOOL synthItal;
724   unsigned int traits = 0;
725   struct nsfont_info *font_info;
726   struct font *font;
727   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
728   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
729   NSString *family;
730   NSFont *nsfont, *sfont;
731   Lisp_Object tem;
732   NSRect brect;
733   Lisp_Object font_object;
734   int fixLeopardBug;
736   block_input ();
738   if (NSFONT_TRACE)
739     {
740       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
741       debug_print (font_entity);
742     }
744   if (pixel_size <= 0)
745     {
746       /* try to get it out of frame params */
747         Lisp_Object tem = get_frame_param (f, Qfontsize);
748         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
749     }
751   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
752   synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
753                                        9);
754   family = ns_get_family (font_entity);
755   if (family == nil)
756     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
757   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
758      when setting family in ns_spec_to_descriptor(). */
759   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
760       traits |= NSBoldFontMask;
761   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F))
762       traits |= NSItalicFontMask;
764   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
765   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
766   nsfont = [fontMgr fontWithFamily: family
767                             traits: traits weight: fixLeopardBug
768                               size: pixel_size];
769   /* if didn't find, try synthetic italic */
770   if (nsfont == nil && synthItal)
771     {
772       nsfont = [fontMgr fontWithFamily: family
773                                 traits: traits & ~NSItalicFontMask
774                                 weight: fixLeopardBug size: pixel_size];
775     }
776 #ifdef NS_IMPL_COCOA
777   /* LastResort not really a family */
778   if (nsfont == nil && [@"LastResort" isEqualToString: family])
779       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
780 #endif
782   if (nsfont == nil)
783     {
784       message_with_string ("*** Warning: font in family `%s' not found",
785                           build_string ([family UTF8String]), 1);
786       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
787     }
789   if (NSFONT_TRACE)
790     NSLog (@"%@\n", nsfont);
792   font_object = font_make_object (VECSIZE (struct nsfont_info),
793                                   font_entity, pixel_size);
794   ASET (font_object, FONT_TYPE_INDEX, nsfont_driver.type);
795   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
796   font = (struct font *) font_info;
797   if (!font)
798     {
799       unblock_input ();
800       return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
801     }
803   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
804   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
806   /* for metrics */
807 #ifdef NS_IMPL_COCOA
808   sfont = [nsfont screenFontWithRenderingMode:
809                     NSFontAntialiasedIntegerAdvancementsRenderingMode];
810 #else
811   sfont = [nsfont screenFont];
812 #endif
814   if (sfont == nil)
815     sfont = nsfont;
817   /* non-metric backend font struct fields */
818   font = (struct font *) font_info;
819   font->pixel_size = [sfont pointSize];
820   font->driver = &nsfont_driver;
821   font->encoding_charset = -1;
822   font->repertory_charset = -1;
823   font->default_ascent = 0;
824   font->vertical_centering = 0;
825   font->baseline_offset = 0;
826   font->relative_compose = 0;
828   {
829     const char *fontName = [[nsfont fontName] UTF8String];
831     /* The values specified by fonts are not always exact. For
832      * example, a 6x8 font could specify that the descender is
833      * -2.00000405... (represented by 0xc000000220000000).  Without
834      * adjustment, the code below would round the descender to -3,
835      * resulting in a font that would be one pixel higher than
836      * intended. */
837     CGFloat adjusted_descender = [sfont descender] + 0.0001;
839 #ifdef NS_IMPL_GNUSTEP
840     font_info->nsfont = sfont;
841 #else
842     font_info->nsfont = nsfont;
843 #endif
844     [font_info->nsfont retain];
846     /* set up ns_font (defined in nsgui.h) */
847     font_info->name = xstrdup (fontName);
848     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
849     font_info->ital =
850       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
852     /* Metrics etc.; some fonts return an unusually large max advance, so we
853        only use it for fonts that have wide characters. */
854     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
855       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
857     brect =  [sfont boundingRectForFont];
859     font_info->underpos = [sfont underlinePosition];
860     font_info->underwidth = [sfont underlineThickness];
861     font_info->size = font->pixel_size;
863     /* max bounds */
864     font->ascent = font_info->max_bounds.ascent = lrint ([sfont ascender]);
865     /* Descender is usually negative.  Use floor to avoid
866        clipping descenders. */
867     font->descent =
868       font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
869     font_info->height =
870       font_info->max_bounds.ascent + font_info->max_bounds.descent;
871     font_info->max_bounds.width = lrint (font_info->width);
872     font_info->max_bounds.lbearing = lrint (brect.origin.x);
873     font_info->max_bounds.rbearing =
874       lrint (brect.size.width - (CGFloat) font_info->width);
876 #ifdef NS_IMPL_COCOA
877     /* set up synthItal and the CG font */
878     font_info->synthItal = synthItal;
879     {
880       ATSFontRef atsFont = ATSFontFindFromPostScriptName
881         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
883       if (atsFont == kATSFontRefUnspecified)
884         {
885           /* see if we can get it by dropping italic (then synthesizing) */
886           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
887               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
888                 fontName], kATSOptionFlagsDefault);
889           if (atsFont != kATSFontRefUnspecified)
890               font_info->synthItal = YES;
891           else
892             {
893               /* last resort fallback */
894               atsFont = ATSFontFindFromPostScriptName
895                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
896             }
897         }
898       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
899     }
900 #endif
902     /* set up metrics portion of font struct */
903     font->ascent = lrint([sfont ascender]);
904     font->descent = -lrint(floor(adjusted_descender));
905     font->space_width = lrint (ns_char_width (sfont, ' '));
906     font->max_width = lrint (font_info->max_bounds.width);
907     font->min_width = font->space_width;  /* Approximate.  */
908     font->average_width = ns_ascii_average_width (sfont);
910     font->height = lrint (font_info->height);
911     font->underline_position = lrint (font_info->underpos);
912     font->underline_thickness = lrint (font_info->underwidth);
914     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
915     font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
916   }
917   unblock_input ();
919   return font_object;
923 /* Close FONT. */
924 static void
925 nsfont_close (struct font *font)
927   struct nsfont_info *font_info = (struct nsfont_info *) font;
929   /* FIXME: font_info may be NULL due to same failure to detect
930      same font that causes need for cache in nsfont_open.  */
931   if (font_info && font_info->name)
932     {
933       int i;
935       for (i = 0; i < 0x100; i++)
936         {
937           xfree (font_info->glyphs[i]);
938           xfree (font_info->metrics[i]);
939         }
940       xfree (font_info->glyphs);
941       xfree (font_info->metrics);
942       [font_info->nsfont release];
943 #ifdef NS_IMPL_COCOA
944       CGFontRelease (font_info->cgfont);
945 #endif
946       xfree (font_info->name);
947       font_info->name = NULL;
948     }
952 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
953    return 1.  If not, return 0.  If a font must be opened to check
954    it, return -1. */
955 static int
956 nsfont_has_char (Lisp_Object entity, int c)
958   return -1;
962 /* Return a glyph code of FONT for character C (Unicode code point).
963    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
964 static unsigned int
965 nsfont_encode_char (struct font *font, int c)
967   struct nsfont_info *font_info = (struct nsfont_info *)font;
968   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
969   unsigned short g;
971   if (c > 0xFFFF)
972     return FONT_INVALID_CODE;
974   /* did we already cache this block? */
975   if (!font_info->glyphs[high])
976     ns_uni_to_glyphs (font_info, high);
978   g = font_info->glyphs[high][low];
979   return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
983 /* Perform the size computation of glyphs of FONT and fill in members
984    of METRICS.  The glyphs are specified by their glyph codes in
985    CODE (length NGLYPHS). */
986 static void
987 nsfont_text_extents (struct font *font, unsigned int *code,
988                      int nglyphs, struct font_metrics *metrics)
990   struct nsfont_info *font_info = (struct nsfont_info *)font;
991   struct font_metrics *pcm;
992   unsigned char high, low;
993   int totalWidth = 0;
994   int i;
996   memset (metrics, 0, sizeof (struct font_metrics));
998   for (i = 0; i < nglyphs; i++)
999     {
1000       /* get metrics for this glyph, filling cache if need be */
1001       /* TODO: get metrics for whole string from an NSLayoutManager
1002                (if not too slow) */
1003       high = (code[i] & 0xFF00) >> 8;
1004       low = code[i] & 0x00FF;
1005       if (!font_info->metrics[high])
1006         ns_glyph_metrics (font_info, high);
1007       pcm = &(font_info->metrics[high][low]);
1009       if (metrics->lbearing > totalWidth + pcm->lbearing)
1010         metrics->lbearing = totalWidth + pcm->lbearing;
1011       if (metrics->rbearing < totalWidth + pcm->rbearing)
1012         metrics->rbearing = totalWidth + pcm->rbearing;
1013       if (metrics->ascent < pcm->ascent)
1014         metrics->ascent = pcm->ascent;
1015       if (metrics->descent < pcm->descent)
1016         metrics->descent = pcm->descent;
1018       totalWidth += pcm->width;
1019     }
1021   metrics->width = totalWidth;
1025 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1026    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND,
1027    fill the background in advance.  It is assured that WITH_BACKGROUND
1028    is false when (FROM > 0 || TO < S->nchars). */
1029 static int
1030 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1031              bool with_background)
1032 /* NOTE: focus and clip must be set */
1034   static unsigned char cbuf[1024];
1035   unsigned char *c = cbuf;
1036 #ifdef NS_IMPL_GNUSTEP
1037 #if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22
1038   static CGFloat advances[1024];
1039   CGFloat *adv = advances;
1040 #else
1041   static float advances[1024];
1042   float *adv = advances;
1043 #endif
1044 #else
1045   static CGSize advances[1024];
1046   CGSize *adv = advances;
1047 #endif
1048   struct face *face;
1049   NSRect r;
1050   struct nsfont_info *font;
1051   NSColor *col, *bgCol;
1052   unsigned short *t = s->char2b;
1053   int i, len, flags;
1054   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1056   block_input ();
1058   font = (struct nsfont_info *)s->face->font;
1059   if (font == NULL)
1060     font = (struct nsfont_info *)FRAME_FONT (s->f);
1062   /* Select face based on input flags */
1063   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
1064     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
1065      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
1066       NS_DUMPGLYPH_NORMAL));
1068   switch (flags)
1069     {
1070     case NS_DUMPGLYPH_CURSOR:
1071       face = s->face;
1072       break;
1073     case NS_DUMPGLYPH_MOUSEFACE:
1074       face = FACE_FROM_ID_OR_NULL (s->f,
1075                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1076       if (!face)
1077         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1078       break;
1079     default:
1080       face = s->face;
1081     }
1083   r.origin.x = s->x;
1084   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1085     r.origin.x += abs (s->face->box_line_width);
1087   r.origin.y = s->y;
1088   r.size.height = FONT_HEIGHT (font);
1090   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1091      NS to render the string, it will come out differently from the individual
1092      character widths added up because of layout processing. */
1093   {
1094     int cwidth, twidth = 0;
1095     int hi, lo;
1096     /* FIXME: composition: no vertical displacement is considered. */
1097     t += from; /* advance into composition */
1098     for (i = from; i < to; i++, t++)
1099       {
1100         hi = (*t & 0xFF00) >> 8;
1101         lo = *t & 0x00FF;
1102         if (isComposite)
1103           {
1104             if (!s->first_glyph->u.cmp.automatic)
1105                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1106             else
1107               {
1108                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1109                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1110                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1111                     cwidth = LGLYPH_WIDTH (glyph);
1112                 else
1113                   {
1114                     cwidth = LGLYPH_WADJUST (glyph);
1115 #ifdef NS_IMPL_GNUSTEP
1116                     *(adv-1) += LGLYPH_XOFF (glyph);
1117 #else
1118                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1119 #endif
1120                   }
1121               }
1122           }
1123         else
1124           {
1125             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1126               ns_glyph_metrics (font, hi);
1127             cwidth = font->metrics[hi][lo].width;
1128           }
1129         twidth += cwidth;
1130 #ifdef NS_IMPL_GNUSTEP
1131         *adv++ = cwidth;
1132         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1133 #else
1134         (*adv++).width = cwidth;
1135 #endif
1136       }
1137     len = adv - advances;
1138     r.size.width = twidth;
1139     *c = 0;
1140   }
1142   /* fill background if requested */
1143   if (with_background && !isComposite)
1144     {
1145       NSRect br = r;
1146       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1147       int mbox_line_width = max (s->face->box_line_width, 0);
1149       if (s->row->full_width_p)
1150         {
1151           if (br.origin.x <= fibw + 1 + mbox_line_width)
1152             {
1153               br.size.width += br.origin.x - mbox_line_width;
1154               br.origin.x = mbox_line_width;
1155             }
1156           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1157                 <= fibw+1)
1158             br.size.width += fibw;
1159         }
1160       if (s->face->box == FACE_NO_BOX)
1161         {
1162           /* expand unboxed top row over internal border */
1163           if (br.origin.y <= fibw + 1 + mbox_line_width)
1164             {
1165               br.size.height += br.origin.y;
1166               br.origin.y = 0;
1167             }
1168         }
1169       else
1170         {
1171           int correction = abs (s->face->box_line_width)+1;
1172           br.origin.y += correction;
1173           br.size.height -= 2*correction;
1174           br.origin.x += correction;
1175           br.size.width -= 2*correction;
1176         }
1178       if (!s->face->stipple)
1179         [(NS_FACE_BACKGROUND (face) != 0
1180           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1181           : FRAME_BACKGROUND_COLOR (s->f)) set];
1182       else
1183         {
1184           struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
1185           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1186         }
1187       NSRectFill (br);
1188     }
1191   /* set up for character rendering */
1192   r.origin.y = y;
1194   col = (NS_FACE_FOREGROUND (face) != 0
1195          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1196          : FRAME_FOREGROUND_COLOR (s->f));
1198   bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
1199            : (NS_FACE_BACKGROUND (face) != 0
1200               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1201               : FRAME_BACKGROUND_COLOR (s->f)));
1203   /* render under GNUstep using DPS */
1204 #ifdef NS_IMPL_GNUSTEP
1205   {
1206     NSGraphicsContext *context = GSCurrentContext ();
1208     DPSgsave (context);
1209     [font->nsfont set];
1211     /* do erase if "foreground" mode */
1212     if (bgCol != nil)
1213       {
1214         [bgCol set];
1215         DPSmoveto (context, r.origin.x, r.origin.y);
1216 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1217         DPSxshow (context, (const char *) cbuf, advances, len);
1218         DPSstroke (context);
1219         [col set];
1220 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1221       }
1223     [col set];
1225     /* draw with DPSxshow () */
1226     DPSmoveto (context, r.origin.x, r.origin.y);
1227     DPSxshow (context, (const char *) cbuf, advances, len);
1228     DPSstroke (context);
1230     DPSgrestore (context);
1231   }
1233 #else  /* NS_IMPL_COCOA */
1234   {
1235     CGContextRef gcontext =
1236       [[NSGraphicsContext currentContext] graphicsPort];
1237     static CGAffineTransform fliptf;
1238     static BOOL firstTime = YES;
1240     if (firstTime)
1241       {
1242         firstTime = NO;
1243         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1244       }
1246     CGContextSaveGState (gcontext);
1248     // Used to be Fix2X (kATSItalicQDSkew), but Fix2X is deprecated
1249     // and kATSItalicQDSkew is 0.25.
1250     fliptf.c =  font->synthItal ? 0.25 : 0.0;
1252     CGContextSetFont (gcontext, font->cgfont);
1253     CGContextSetFontSize (gcontext, font->size);
1254     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1255       CGContextSetShouldAntialias (gcontext, 0);
1256     else
1257       CGContextSetShouldAntialias (gcontext, 1);
1259     CGContextSetTextMatrix (gcontext, fliptf);
1261     if (bgCol != nil)
1262       {
1263         /* foreground drawing; erase first to avoid overstrike */
1264         [bgCol set];
1265         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1266         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1267         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1268         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1269       }
1271     [col set];
1273     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1274     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1275                                      advances, len);
1277     if (face->overstrike)
1278       {
1279         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1280         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1281                                          advances, len);
1282       }
1284     CGContextRestoreGState (gcontext);
1285   }
1286 #endif  /* NS_IMPL_COCOA */
1288   unblock_input ();
1289   return to-from;
1294 /* ==========================================================================
1296     Font glyph and metrics caching functions
1298    ========================================================================== */
1300 /* Find and cache corresponding glyph codes for unicode values in given
1301    hi-byte block of 256. */
1302 static void
1303 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1305 #ifdef NS_IMPL_COCOA
1306   static EmacsGlyphStorage *glyphStorage;
1307   static char firstTime = 1;
1308 #endif
1309   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1310   unsigned int i, g, idx;
1311   unsigned short *glyphs;
1313   if (NSFONT_TRACE)
1314     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1315             font_info, block);
1317   block_input ();
1319 #ifdef NS_IMPL_COCOA
1320   if (firstTime)
1321     {
1322       firstTime = 0;
1323       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1324     }
1325 #endif
1327   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1328   if (!unichars || !(font_info->glyphs[block]))
1329     emacs_abort ();
1331   /* create a string containing all Unicode characters in this block */
1332   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1333     if (idx < 0xD800 || idx > 0xDFFF)
1334       unichars[i] = idx;
1335     else
1336       unichars[i] = 0xFEFF;
1337   unichars[0x100] = 0;
1339   {
1340 #ifdef NS_IMPL_COCOA
1341     NSString *allChars = [[NSString alloc]
1342                                initWithCharactersNoCopy: unichars
1343                                                  length: 0x100
1344                                            freeWhenDone: NO];
1345     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1346     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1347     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1348     NSUInteger gInd = 0, cInd = 0;
1350     [glyphStorage setString: allChars font: font_info->nsfont];
1351     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1352                         desiredNumberOfCharacters: glyphStorage->maxChar
1353                                        glyphIndex: &gInd characterIndex: &cInd];
1354 #endif
1355     glyphs = font_info->glyphs[block];
1356     for (i = 0; i < 0x100; i++, glyphs++)
1357       {
1358 #ifdef NS_IMPL_GNUSTEP
1359         g = unichars[i];
1360 #else
1361         g = glyphStorage->cglyphs[i];
1362         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1363         if (g > numGlyphs || g == NSNullGlyph)
1364           g = INVALID_GLYPH; /* hopefully unused... */
1365 #endif
1366         *glyphs = g;
1367       }
1369 #ifdef NS_IMPL_COCOA
1370     [allChars release];
1371 #endif
1372   }
1374   unblock_input ();
1375   xfree (unichars);
1379 /* Determine and cache metrics for corresponding glyph codes in given
1380    hi-byte block of 256. */
1381 static void
1382 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1384   unsigned int i, g;
1385   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1386   NSFont *sfont;
1387   struct font_metrics *metrics;
1389   if (NSFONT_TRACE)
1390     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1391             font_info, block);
1393 #ifdef NS_IMPL_GNUSTEP
1394   /* not implemented yet (as of startup 0.18), so punt */
1395   if (numGlyphs == 0)
1396     numGlyphs = 0x10000;
1397 #endif
1399   block_input ();
1400 #ifdef NS_IMPL_COCOA
1401   sfont = [font_info->nsfont screenFontWithRenderingMode:
1402                       NSFontAntialiasedIntegerAdvancementsRenderingMode];
1403 #else
1404   sfont = [font_info->nsfont screenFont];
1405 #endif
1407   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1408   if (!(font_info->metrics[block]))
1409     emacs_abort ();
1411   metrics = font_info->metrics[block];
1412   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1413     {
1414       CGFloat w, lb, rb;
1415       NSRect r = [sfont boundingRectForGlyph: g];
1417       w = max ([sfont advancementForGlyph: g].width, 2.0);
1418       metrics->width = lrint (w);
1420       lb = r.origin.x;
1421       rb = r.size.width - w;
1422       // Add to bearing for LCD smoothing.  We don't know if it is there.
1423       if (lb < 0)
1424         metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1425       if (font_info->ital)
1426         rb += (CGFloat) (0.22F * font_info->height);
1427       metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1429       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1430  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1431       metrics->ascent = r.size.height - metrics->descent;
1432 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1433     }
1434   unblock_input ();
1438 #ifdef NS_IMPL_COCOA
1439 /* helper for font glyph setup */
1440 @implementation EmacsGlyphStorage
1442 - init
1444   return [self initWithCapacity: 1024];
1447 - initWithCapacity: (unsigned long) c
1449   self = [super init];
1450   maxChar = 0;
1451   maxGlyph = 0;
1452   dict = [NSMutableDictionary new];
1453   cglyphs = xmalloc (c * sizeof (CGGlyph));
1454   return self;
1457 - (void) dealloc
1459   if (attrStr != nil)
1460     [attrStr release];
1461   [dict release];
1462   xfree (cglyphs);
1463   [super dealloc];
1466 - (void) setString: (NSString *)str font: (NSFont *)font
1468   [dict setObject: font forKey: NSFontAttributeName];
1469   if (attrStr != nil)
1470     [attrStr release];
1471   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1472   maxChar = [str length];
1473   maxGlyph = 0;
1476 /* NSGlyphStorage protocol */
1477 - (NSUInteger)layoutOptions
1479   return 0;
1482 - (NSAttributedString *)attributedString
1484   return attrStr;
1487 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1488         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1489         characterIndex: (NSUInteger)charIndex
1491   len = glyphIndex+length;
1492   for (i =glyphIndex; i<len; i++)
1493     cglyphs[i] = glyphs[i-glyphIndex];
1494   if (len > maxGlyph)
1495     maxGlyph = len;
1498 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1499         forGlyphAtIndex: (NSUInteger)glyphIndex
1501   return;
1504 @end
1505 #endif /* NS_IMPL_COCOA */
1508 /* Debugging */
1509 void
1510 ns_dump_glyphstring (struct glyph_string *s)
1512   int i;
1514   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1515 "overlap = %d, bg_filled = %d:",
1516            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1517            s->row->overlapping_p, s->background_filled_p);
1518   for (i =0; i<s->nchars; i++)
1519     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1520   fprintf (stderr, "\n");
1524 void
1525 syms_of_nsfont (void)
1527   nsfont_driver.type = Qns;
1528   register_font_driver (&nsfont_driver, NULL);
1529   DEFSYM (Qcondensed, "condensed");
1530   DEFSYM (Qexpanded, "expanded");
1531   DEFSYM (Qapple, "apple");
1532   DEFSYM (Qmedium, "medium");
1533   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1534                doc: /* Internal use: maps font registry to Unicode script. */);
1536   ascii_printable = NULL;