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