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