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