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