Auto-commit of generated files.
[emacs.git] / src / nsfont.m
blob6f9294e082ab0a76b7129b015ca18407ea6b4ae7
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;
244     NSString *cstr = [NSString stringWithFormat: @"%c", c];
245 #ifdef NS_IMPL_COCOA
246     NSGlyph glyph = [sfont glyphWithName: cstr];
247     if (glyph)
248       {
249         float w = [sfont advancementForGlyph: glyph].width;
250         if (w >= 1.5)
251             return w;
252       }
253 #endif
254     {
255       NSDictionary *attrsDictionary =
256         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
257       w = [cstr sizeWithAttributes: attrsDictionary].width;
258     }
259     return max (w, 2.0);
263 /* Return whether set1 covers set2 to a reasonable extent given by pct.
264    We check, out of each 16 Unicode char range containing chars in set2,
265    whether at least one character is present in set1.
266    This must be true for pct of the pairs to consider it covering. */
267 static BOOL
268 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
270     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
271     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
272     int i, off = 0, tot = 0;
274     /* Work around what appears to be a GNUstep bug.
275        See <http://bugs.gnu.org/11853>.  */
276     if (! (bytes1 && bytes2))
277       return NO;
279     for (i=0; i<4096; i++, bytes1++, bytes2++)
280         if (*bytes2)
281           {
282             tot++;
283             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
284                 off++;
285           }
286 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
287     return (float)off / tot < 1.0 - pct;
291 /* Convert :lang property to a script.  Use of :lang property by font backend
292    seems to be limited for now (2009/05) to ja, zh, and ko. */
293 static NSString
294 *ns_lang_to_script (Lisp_Object lang)
296     if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
297         return @"han";
298     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
299              have more characters. */
300     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
301         return @"han";
302     else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
303         return @"hangul";
304     else
305         return @"";
309 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
310    everyone just use some standard Unicode names for these?) */
311 static NSString
312 *ns_otf_to_script (Lisp_Object otf)
314     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
315     return CONSP (script)
316         ? [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (XCDR ((script))))]
317         : @"";
321 /* Convert a font registry, such as  */
322 static NSString
323 *ns_registry_to_script (char *reg)
325     Lisp_Object script, r, rts = Vns_reg_to_script;
326     while CONSP (rts)
327       {
328         r = XCAR (XCAR (rts));
329         if (!strncmp(SSDATA(r), reg, strlen(SSDATA(r))))
330           {
331             script = XCDR (XCAR (rts));
332             return [NSString stringWithUTF8String: SSDATA (SYMBOL_NAME (script))];
333           }
334         rts = XCDR (rts);
335       }
336     return  @"";
340 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
341    plus registry regular property, for something that can be mapped to a
342    Unicode script.  Empty string returned if no script spec found. */
343 static NSString
344 *ns_get_req_script (Lisp_Object font_spec)
346     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
347     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
349     /* The extra-bundle properties have priority. */
350     for ( ; CONSP (extra); extra = XCDR (extra))
351       {
352         Lisp_Object tmp = XCAR (extra);
353         if (CONSP (tmp))
354           {
355             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
356             if (EQ (key, QCscript) && SYMBOLP (val))
357                 return [NSString stringWithUTF8String:
358                             SSDATA (SYMBOL_NAME (val))];
359             if (EQ (key, QClang) && SYMBOLP (val))
360                 return ns_lang_to_script (val);
361             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
362                 return ns_otf_to_script (val);
363           }
364       }
366     /* If we get here, check the charset portion of the registry. */
367     if (! NILP (reg))
368       {
369         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
370            (which causes box rendering if we don't treat it like iso8858-1)
371            but also for ascii (which causes unnecessary font substitution). */
372 #if 0
373         if (EQ (reg, Qiso10646_1))
374           reg = Qiso8859_1;
375 #endif
376         return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
377       }
379     return @"";
383 /* This small function is static in fontset.c.  If it can be made public for
384    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
385 static void
386 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
388     if (EQ (XCAR (arg), val))
389       {
390         if (CONSP (range))
391           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
392         else
393           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
394       }
398 /* Use the Unicode range information in Vchar_script_table to convert a script
399    name into an NSCharacterSet. */
400 static NSCharacterSet
401 *ns_script_to_charset (NSString *scriptName)
403     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
404     Lisp_Object script = intern ([scriptName UTF8String]);
405     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
407     if (! NILP (Fmemq (script, script_list)))
408       {
409         Lisp_Object ranges, range_list;
411         ranges = Fcons (script, Qnil);
412         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
413                         ranges);
414         range_list = Fnreverse (XCDR (ranges));
415         if (! NILP (range_list))
416           {
417             for (; CONSP (range_list); range_list = XCDR (range_list))
418               {
419                 int start = XINT (XCAR (XCAR (range_list)));
420                 int end = XINT (XCDR (XCAR (range_list)));
421                 if (NSFONT_TRACE)
422                     debug_print (XCAR (range_list));
423                 if (end < 0x10000)
424                     [charset addCharactersInRange:
425                         NSMakeRange (start, end-start)];
426               }
427           }
428       }
429     return charset;
433 /* Return an array of font families containing characters for the given
434    script, for the given coverage criterion, including at least LastResort.
435    Results are cached by script for faster access.
436    If none are found, we reduce the percentage and try again, until 5%.
437    This provides a font with at least some characters if such can be found.
438    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
439    (b) need approximate match as fonts covering full Unicode ranges are rare. */
440 static NSSet
441 *ns_get_covering_families (NSString *script, float pct)
443     static NSMutableDictionary *scriptToFamilies = nil;
444     NSMutableSet *families;
446     if (NSFONT_TRACE)
447         NSLog(@"Request covering families for script: '%@'", script);
449     if (scriptToFamilies == nil)
450         scriptToFamilies = [[NSMutableDictionary alloc] init];
452     if ((families = [scriptToFamilies objectForKey: script]) == nil)
453       {
454         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
455         NSArray *allFamilies = [fontMgr availableFontFamilies];
457         if ([script length] == 0)
458             families = [NSMutableSet setWithArray: allFamilies];
459         else
460           {
461             NSCharacterSet *charset = ns_script_to_charset (script);
462             NSString *family;
463             families = [NSMutableSet setWithCapacity: 10];
464             while (1)
465               {
466                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
467                 while ((family = [allFamiliesEnum nextObject]))
468                   {
469                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
470                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
471                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
472                     if (fset == nil)
473                       fset = [NSCharacterSet characterSetWithRange:
474                                                NSMakeRange (0, 127)];
475                     if (ns_charset_covers(fset, charset, pct))
476                         [families addObject: family];
477                   }
478                 pct -= 0.2;
479                 if ([families count] > 0 || pct < 0.05)
480                     break;
481               }
482             [charset release];
483           }
484 #ifdef NS_IMPL_COCOA
485         if ([families count] == 0)
486             [families addObject: @"LastResort"];
487 #endif
488         [scriptToFamilies setObject: families forKey: script];
489       }
491     if (NSFONT_TRACE)
492         NSLog(@"    returning %d families", [families count]);
493     return families;
497 /* Implementation for list() and match().  List() can return nil, match()
498 must return something.  Strategy is to drop family name from attribute
499 matching set for match. */
500 static Lisp_Object
501 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
503     Lisp_Object tem, list = Qnil;
504     NSFontDescriptor *fdesc, *desc;
505     NSMutableSet *fkeys;
506     NSArray *matchingDescs;
507     NSEnumerator *dEnum;
508     NSString *family;
509     NSSet *cFamilies;
510     BOOL foundItal = NO;
512     if (NSFONT_TRACE)
513       {
514         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
515                  (isMatch ? "match" : "list"));
516         debug_print (font_spec);
517       }
519     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
521     fdesc = ns_spec_to_descriptor (font_spec);
522     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
523     if (isMatch)
524         [fkeys removeObject: NSFontFamilyAttribute];
526     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
527     if (NSFONT_TRACE)
528         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
529               [matchingDescs count]);
531     for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
532       {
533         if (![cFamilies containsObject:
534                  [desc objectForKey: NSFontFamilyAttribute]])
535             continue;
536         tem = ns_descriptor_to_entity (desc,
537                                          AREF (font_spec, FONT_EXTRA_INDEX),
538                                        NULL);
539         if (isMatch)
540           return tem;
541         list = Fcons (tem, list);
542         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
543             foundItal = YES;
544       }
546     /* Add synthItal member if needed. */
547     family = [fdesc objectForKey: NSFontFamilyAttribute];
548     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
549       {
550         NSFontDescriptor *s1 = [NSFontDescriptor new];
551         NSFontDescriptor *sDesc
552           = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
553               fontDescriptorWithFamily: family];
554         list = Fcons (ns_descriptor_to_entity (sDesc,
555                                          AREF (font_spec, FONT_EXTRA_INDEX),
556                                          "synthItal"), list);
557         [s1 release];
558       }
560     /* Return something if was a match and nothing found. */
561     if (isMatch)
562       return ns_fallback_entity ();
564     if (NSFONT_TRACE)
565         fprintf (stderr, "    Returning %"pI"d entities.\n",
566                  XINT (Flength (list)));
568     return list;
573 /* ==========================================================================
575     Font driver implementation
577    ========================================================================== */
580 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
581 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
582 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
583 static Lisp_Object nsfont_list_family (Lisp_Object frame);
584 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
585                                  int pixel_size);
586 static void nsfont_close (FRAME_PTR f, struct font *font);
587 static int nsfont_has_char (Lisp_Object entity, int c);
588 static unsigned int nsfont_encode_char (struct font *font, int c);
589 static int nsfont_text_extents (struct font *font, unsigned int *code,
590                                 int nglyphs, struct font_metrics *metrics);
591 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
592                         int with_background);
594 struct font_driver nsfont_driver =
595   {
596     0,                          /* Qns */
597     1,                          /* case sensitive */
598     nsfont_get_cache,
599     nsfont_list,
600     nsfont_match,
601     nsfont_list_family,
602     NULL,                       /*free_entity */
603     nsfont_open,
604     nsfont_close,
605     NULL,                       /* prepare_face */
606     NULL,                       /* done_face */
607     nsfont_has_char,
608     nsfont_encode_char,
609     nsfont_text_extents,
610     nsfont_draw,
611     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
612                  anchor_point, otf_capability, otf_driver,
613                  start_for_frame, end_for_frame, shape */
614   };
617 /* Return a cache of font-entities on FRAME.  The cache must be a
618    cons whose cdr part is the actual cache area.  */
619 static Lisp_Object
620 nsfont_get_cache (FRAME_PTR frame)
622   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
623   return (dpyinfo->name_list_element);
627 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
628    **list** of font-entities.  This and match () are sole APIs that allocate
629    font-entities.  Properties to be considered (2009/05/19) are:
630    regular: foundry, family, adstyle, registry
631    extended: script, lang, otf
632   "Extended" properties are not part of the vector but get stored as
633    lisp properties under FONT_EXTRA_INDEX.
635    The returned entities should have type set (to 'ns), plus the following:
636    foundry, family, adstyle, registry,
637    weight, slant, width, size (0 if scalable),
638    dpi, spacing, avgwidth (0 if scalable)  */
639 static Lisp_Object
640 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
642     return ns_findfonts (font_spec, NO);
646 /* Return a font entity most closely matching with FONT_SPEC on
647    FRAME.  The closeness is determined by the font backend, thus
648    `face-font-selection-order' is ignored here.
649    Properties to be considered are same as for list(). */
650 static Lisp_Object
651 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
653     return ns_findfonts(font_spec, YES);
657 /* List available families.  The value is a list of family names
658    (symbols). */
659 static Lisp_Object
660 nsfont_list_family (Lisp_Object frame)
662   Lisp_Object list = Qnil;
663   NSEnumerator *families =
664     [[[NSFontManager sharedFontManager] availableFontFamilies]
665       objectEnumerator];
666   NSString *family;
667   while ((family = [families nextObject]))
668       list = Fcons (intern ([family UTF8String]), list);
669   /* FIXME: escape the name? */
671   if (NSFONT_TRACE)
672     fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
673              XINT (Flength (list)));
675   return list;
679 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
680    scalable, open it with PIXEL_SIZE.  */
681 static Lisp_Object
682 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
684   BOOL synthItal;
685   unsigned int traits = 0;
686   struct nsfont_info *font_info;
687   struct font *font;
688   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
689   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
690   NSString *family;
691   NSFont *nsfont, *sfont;
692   Lisp_Object tem;
693   NSRect brect;
694   Lisp_Object font_object;
695   int fixLeopardBug;
696   static NSMutableDictionary *fontCache = nil;
697   NSNumber *cached;
699   /* 2008/03/08: The same font may end up being requested for different
700      entities, due to small differences in numeric values or other issues,
701      or for different copies of the same entity.  Therefore we cache to
702      avoid creating multiple struct font objects (with metrics cache, etc.)
703      for the same NSFont object. */
704   if (fontCache == nil)
705     fontCache = [[NSMutableDictionary alloc] init];
707   if (NSFONT_TRACE)
708     {
709       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
710       debug_print (font_entity);
711     }
713   if (pixel_size <= 0)
714     {
715       /* try to get it out of frame params */
716         Lisp_Object tem = get_frame_param (f, Qfontsize);
717         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
718     }
720   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
721   synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
722                                        9);
723   family = ns_get_family (font_entity);
724   if (family == nil)
725     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
726   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
727      when setting family in ns_spec_to_descriptor(). */
728   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
729       traits |= NSBoldFontMask;
730   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
731       traits |= NSItalicFontMask;
733   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
734   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
735   nsfont = [fontMgr fontWithFamily: family
736                             traits: traits weight: fixLeopardBug
737                               size: pixel_size];
738   /* if didn't find, try synthetic italic */
739   if (nsfont == nil && synthItal)
740     {
741       nsfont = [fontMgr fontWithFamily: family
742                                 traits: traits & ~NSItalicFontMask
743                                 weight: fixLeopardBug size: pixel_size];
744     }
745 #ifdef NS_IMPL_COCOA
746   /* LastResort not really a family */
747   if (nsfont == nil && [@"LastResort" isEqualToString: family])
748       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
749 #endif
751   if (nsfont == nil)
752     {
753       message_with_string ("*** Warning: font in family '%s' not found",
754                           build_string ([family UTF8String]), 1);
755       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
756     }
758   if (NSFONT_TRACE)
759     NSLog (@"%@\n", nsfont);
761   /* Check the cache */
762   cached = [fontCache objectForKey: nsfont];
763   if (cached != nil && !synthItal)
764     {
765       if (NSFONT_TRACE)
766         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
767       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
768       XHASH (font_object) = [cached unsignedLongValue];
769       return font_object;
770     }
771   else
772     {
773       font_object = font_make_object (VECSIZE (struct nsfont_info),
774                                       font_entity, pixel_size);
775       if (!synthItal)
776         [fontCache setObject: [NSNumber numberWithUnsignedLong:
777                                           (unsigned long) XHASH (font_object)]
778                       forKey: nsfont];
779     }
781   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
782   font = (struct font *) font_info;
783   if (!font)
784     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
786   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
787   font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
789   BLOCK_INPUT;
791   /* for metrics */
792   sfont = [nsfont screenFont];
793   if (sfont == nil)
794     sfont = nsfont;
796   /* non-metric backend font struct fields */
797   font = (struct font *) font_info;
798   font->pixel_size = [sfont pointSize];
799   font->driver = &nsfont_driver;
800   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
801   font->encoding_charset = -1;
802   font->repertory_charset = -1;
803   font->default_ascent = 0;
804   font->vertical_centering = 0;
805   font->baseline_offset = 0;
806   font->relative_compose = 0;
807   font->font_encoder = NULL;
809   font->props[FONT_FORMAT_INDEX] = Qns;
810   font->props[FONT_FILE_INDEX] = Qnil;
812   {
813     const char *fontName = [[nsfont fontName] UTF8String];
815     /* The values specified by fonts are not always exact. For
816      * example, a 6x8 font could specify that the descender is
817      * -2.00000405... (represented by 0xc000000220000000).  Without
818      * adjustment, the code below would round the descender to -3,
819      * resulting in a font that would be one pixel higher than
820      * intended. */
821     CGFloat adjusted_descender = [sfont descender] + 0.0001;
823 #ifdef NS_IMPL_GNUSTEP
824     font_info->nsfont = sfont;
825 #else
826     font_info->nsfont = nsfont;
827 #endif
828     [font_info->nsfont retain];
830     /* set up ns_font (defined in nsgui.h) */
831     font_info->name = xstrdup (fontName);
832     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
833     font_info->ital =
834       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
836     /* Metrics etc.; some fonts return an unusually large max advance, so we
837        only use it for fonts that have wide characters. */
838     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
839       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
841     brect =  [sfont boundingRectForFont];
843     font_info->underpos = [sfont underlinePosition];
844     font_info->underwidth = [sfont underlineThickness];
845     font_info->size = font->pixel_size;
847     /* max bounds */
848     font_info->max_bounds.ascent = lrint ([sfont ascender]);
849     /* Descender is usually negative.  Use floor to avoid
850        clipping descenders. */
851     font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
852     font_info->height =
853       font_info->max_bounds.ascent + font_info->max_bounds.descent;
854     font_info->max_bounds.width = lrint (font_info->width);
855     font_info->max_bounds.lbearing = lrint (brect.origin.x);
856     font_info->max_bounds.rbearing =
857       lrint (brect.size.width - font_info->width);
859 #ifdef NS_IMPL_COCOA
860     /* set up synthItal and the CG font */
861     font_info->synthItal = synthItal;
862     {
863       ATSFontRef atsFont = ATSFontFindFromPostScriptName
864         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
866       if (atsFont == kATSFontRefUnspecified)
867         {
868           /* see if we can get it by dropping italic (then synthesizing) */
869           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
870               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
871                 fontName], kATSOptionFlagsDefault);
872           if (atsFont != kATSFontRefUnspecified)
873               font_info->synthItal = YES;
874           else
875             {
876               /* last resort fallback */
877               atsFont = ATSFontFindFromPostScriptName
878                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
879             }
880         }
881       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
882     }
883 #endif
885     /* set up metrics portion of font struct */
886     font->ascent = lrint([sfont ascender]);
887     font->descent = -lrint(floor(adjusted_descender));
888     font->min_width = ns_char_width(sfont, '|');
889     font->space_width = lrint (ns_char_width (sfont, ' '));
890     font->average_width = lrint (font_info->width);
891     font->max_width = lrint (font_info->max_bounds.width);
892     font->height = lrint (font_info->height);
893     font->underline_position = lrint (font_info->underpos);
894     font->underline_thickness = lrint (font_info->underwidth);
896     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
897     font->props[FONT_FULLNAME_INDEX] =
898       make_unibyte_string (font_info->name, strlen (font_info->name));
899   }
900   UNBLOCK_INPUT;
902   return font_object;
906 /* Close FONT on frame F. */
907 static void
908 nsfont_close (FRAME_PTR f, struct font *font)
910   struct nsfont_info *font_info = (struct nsfont_info *)font;
911   int i;
913   /* FIXME: this occurs apparently due to same failure to detect same font
914             that causes need for cache in nsfont_open () */
915   if (!font_info)
916       return;
918   for (i =0; i<0x100; i++)
919     {
920       xfree (font_info->glyphs[i]);
921       xfree (font_info->metrics[i]);
922     }
923   [font_info->nsfont release];
924 #ifdef NS_IMPL_COCOA
925   CGFontRelease (font_info->cgfont);
926 #endif
927   xfree (font_info->name);
928   xfree (font_info);
932 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
933    return 1.  If not, return 0.  If a font must be opened to check
934    it, return -1. */
935 static int
936 nsfont_has_char (Lisp_Object entity, int c)
938   return -1;
942 /* Return a glyph code of FONT for character C (Unicode code point).
943    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
944 static unsigned int
945 nsfont_encode_char (struct font *font, int c)
947   struct nsfont_info *font_info = (struct nsfont_info *)font;
948   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
949   unsigned short g;
951   if (c > 0xFFFF)
952     return FONT_INVALID_CODE;
954   /* did we already cache this block? */
955   if (!font_info->glyphs[high])
956     ns_uni_to_glyphs (font_info, high);
958   g = font_info->glyphs[high][low];
959   return g == 0xFFFF ? FONT_INVALID_CODE : g;
963 /* Perform the size computation of glyphs of FONT and fill in members
964    of METRICS.  The glyphs are specified by their glyph codes in
965    CODE (length NGLYPHS). */
966 static int
967 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
968                      struct font_metrics *metrics)
970   struct nsfont_info *font_info = (struct nsfont_info *)font;
971   struct font_metrics *pcm;
972   unsigned char high, low;
973   int totalWidth = 0;
974   int i;
976   memset (metrics, 0, sizeof (struct font_metrics));
978   for (i =0; i<nglyphs; i++)
979     {
980       /* get metrics for this glyph, filling cache if need be */
981       /* TODO: get metrics for whole string from an NSLayoutManager
982                (if not too slow) */
983       high = (code[i] & 0xFF00) >> 8;
984       low = code[i] & 0x00FF;
985       if (!font_info->metrics[high])
986         ns_glyph_metrics (font_info, high);
987       pcm = &(font_info->metrics[high][low]);
989       if (metrics->lbearing > totalWidth + pcm->lbearing)
990         metrics->lbearing = totalWidth + pcm->lbearing;
991       if (metrics->rbearing < totalWidth + pcm->rbearing)
992         metrics->rbearing = totalWidth + pcm->rbearing;
993       if (metrics->ascent < pcm->ascent)
994         metrics->ascent = pcm->ascent;
995       if (metrics->descent < pcm->descent)
996         metrics->descent = pcm->descent;
998       totalWidth += pcm->width;
999     }
1001   metrics->width = totalWidth;
1003   return totalWidth; /* not specified in doc, but xfont.c does it */
1007 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1008    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
1009    is nonzero, fill the background in advance.  It is assured that
1010    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1011 static int
1012 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1013              int with_background)
1014 /* NOTE: focus and clip must be set
1015      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1017   static char cbuf[1024];
1018   char *c = cbuf;
1019 #ifdef NS_IMPL_GNUSTEP
1020   static float advances[1024];
1021   float *adv = advances;
1022 #else
1023   static CGSize advances[1024];
1024   CGSize *adv = advances;
1025 #endif
1026   struct face *face;
1027   NSRect r;
1028   struct nsfont_info *font = ns_tmp_font;
1029   NSColor *col, *bgCol;
1030   unsigned short *t = s->char2b;
1031   int i, len;
1032   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1033   int end = isComposite ? s->cmp_to : s->nchars;
1035   /* Select face based on input flags */
1036   switch (ns_tmp_flags)
1037     {
1038     case NS_DUMPGLYPH_CURSOR:
1039       face = s->face;
1040       break;
1041     case NS_DUMPGLYPH_MOUSEFACE:
1042       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1043       if (!face)
1044         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1045       break;
1046     default:
1047       face = s->face;
1048     }
1050   r.origin.x = s->x;
1051   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1052     r.origin.x += abs (s->face->box_line_width);
1054   r.origin.y = s->y;
1055   r.size.height = FONT_HEIGHT (font);
1057   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1058      NS to render the string, it will come out differently from the individual
1059      character widths added up because of layout processing. */
1060   {
1061     int cwidth, twidth = 0;
1062     int hi, lo;
1063     /* FIXME: composition: no vertical displacement is considered. */
1064     t += s->cmp_from; /* advance into composition */
1065     for (i = s->cmp_from; i < end; i++, t++)
1066       {
1067         hi = (*t & 0xFF00) >> 8;
1068         lo = *t & 0x00FF;
1069         if (isComposite)
1070           {
1071             if (!s->first_glyph->u.cmp.automatic)
1072                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1073             else
1074               {
1075                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1076                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1077                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1078                     cwidth = LGLYPH_WIDTH (glyph);
1079                 else
1080                   {
1081                     cwidth = LGLYPH_WADJUST (glyph);
1082 #ifdef NS_IMPL_GNUSTEP
1083                     *(adv-1) += LGLYPH_XOFF (glyph);
1084 #else
1085                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1086 #endif
1087                   }
1088               }
1089           }
1090         else
1091           {
1092             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1093               ns_glyph_metrics (font, hi);
1094             cwidth = font->metrics[hi][lo].width;
1095           }
1096         twidth += cwidth;
1097 #ifdef NS_IMPL_GNUSTEP
1098         *adv++ = cwidth;
1099         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1100 #else
1101         (*adv++).width = cwidth;
1102 #endif
1103       }
1104     len = adv - advances;
1105     r.size.width = twidth;
1106     *c = 0;
1107   }
1109   /* fill background if requested */
1110   if (with_background && !isComposite)
1111     {
1112       NSRect br = r;
1113       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1114       int mbox_line_width = max (s->face->box_line_width, 0);
1116       if (s->row->full_width_p)
1117         {
1118           if (br.origin.x <= fibw + 1 + mbox_line_width)
1119             {
1120               br.size.width += br.origin.x - mbox_line_width;
1121               br.origin.x = mbox_line_width;
1122             }
1123           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1124                 <= fibw+1)
1125             br.size.width += fibw;
1126         }
1127       if (s->face->box == FACE_NO_BOX)
1128         {
1129           /* expand unboxed top row over internal border */
1130           if (br.origin.y <= fibw + 1 + mbox_line_width)
1131             {
1132               br.size.height += br.origin.y;
1133               br.origin.y = 0;
1134             }
1135         }
1136       else
1137         {
1138           int correction = abs (s->face->box_line_width)+1;
1139           br.origin.y += correction;
1140           br.size.height -= 2*correction;
1141           br.origin.x += correction;
1142           br.size.width -= 2*correction;
1143         }
1145       if (!s->face->stipple)
1146         [(NS_FACE_BACKGROUND (face) != 0
1147           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1148           : FRAME_BACKGROUND_COLOR (s->f)) set];
1149       else
1150         {
1151           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1152           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1153         }
1154       NSRectFill (br);
1155     }
1158   /* set up for character rendering */
1159   r.origin.y = s->ybase;
1161   col = (NS_FACE_FOREGROUND (face) != 0
1162          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1163          : FRAME_FOREGROUND_COLOR (s->f));
1164   /* FIXME: find another way to pass this */
1165   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1166            : (NS_FACE_BACKGROUND (face) != 0
1167               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1168               : FRAME_BACKGROUND_COLOR (s->f)));
1170   /* render under GNUstep using DPS */
1171 #ifdef NS_IMPL_GNUSTEP
1172   {
1173     NSGraphicsContext *context = GSCurrentContext ();
1175     DPSgsave (context);
1176     [font->nsfont set];
1178     /* do erase if "foreground" mode */
1179     if (bgCol != nil)
1180       {
1181         [bgCol set];
1182         DPSmoveto (context, r.origin.x, r.origin.y);
1183 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1184         DPSxshow (context, cbuf, advances, len);
1185         DPSstroke (context);
1186         [col set];
1187 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1188       }
1190     [col set];
1192     /* draw with DPSxshow () */
1193     DPSmoveto (context, r.origin.x, r.origin.y);
1194     DPSxshow (context, cbuf, advances, len);
1195     DPSstroke (context);
1197     DPSgrestore (context);
1198   }
1200 #else  /* NS_IMPL_COCOA */
1201   {
1202     CGContextRef gcontext =
1203       [[NSGraphicsContext currentContext] graphicsPort];
1204     static CGAffineTransform fliptf;
1205     static BOOL firstTime = YES;
1207     if (firstTime)
1208       {
1209         firstTime = NO;
1210         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1211       }
1213     CGContextSaveGState (gcontext);
1215     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1217     CGContextSetFont (gcontext, font->cgfont);
1218     CGContextSetFontSize (gcontext, font->size);
1219     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1220       CGContextSetShouldAntialias (gcontext, 0);
1221     else
1222       CGContextSetShouldAntialias (gcontext, 1);
1224     CGContextSetTextMatrix (gcontext, fliptf);
1226     if (bgCol != nil)
1227       {
1228         /* foreground drawing; erase first to avoid overstrike */
1229         [bgCol set];
1230         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1231         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1232         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1233         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1234       }
1236     [col set];
1238     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1239     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1240                                     advances, len);
1242     if (face->overstrike)
1243       {
1244         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1245         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1246                                         advances, len);
1247       }
1249     CGContextRestoreGState (gcontext);
1250   }
1251 #endif  /* NS_IMPL_COCOA */
1253   /* Draw underline, overline, strike-through. */
1254   ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1256   return to-from;
1261 /* ==========================================================================
1263     Font glyph and metrics caching functions
1265    ========================================================================== */
1267 /* Find and cache corresponding glyph codes for unicode values in given
1268    hi-byte block of 256. */
1269 static void
1270 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1272 #ifdef NS_IMPL_COCOA
1273   static EmacsGlyphStorage *glyphStorage;
1274   static char firstTime = 1;
1275 #endif
1276   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1277   unsigned int i, g, idx;
1278   unsigned short *glyphs;
1280   if (NSFONT_TRACE)
1281     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1282             font_info, block);
1284  BLOCK_INPUT;
1286 #ifdef NS_IMPL_COCOA
1287   if (firstTime)
1288     {
1289       firstTime = 0;
1290       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1291     }
1292 #endif
1294   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1295   if (!unichars || !(font_info->glyphs[block]))
1296     abort ();
1298   /* create a string containing all Unicode characters in this block */
1299   for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1300     if (idx < 0xD800 || idx > 0xDFFF)
1301       unichars[i] = idx;
1302     else
1303       unichars[i] = 0xFEFF;
1304   unichars[0x100] = 0;
1306   {
1307 #ifdef NS_IMPL_COCOA
1308     NSString *allChars = [[NSString alloc]
1309                                initWithCharactersNoCopy: unichars
1310                                                  length: 0x100
1311                                            freeWhenDone: NO];
1312     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1313     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1314     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1315     NSUInteger gInd = 0, cInd = 0;
1317     [glyphStorage setString: allChars font: font_info->nsfont];
1318     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1319                         desiredNumberOfCharacters: glyphStorage->maxChar
1320                                        glyphIndex: &gInd characterIndex: &cInd];
1321 #endif
1322     glyphs = font_info->glyphs[block];
1323     for (i = 0; i < 0x100; i++, glyphs++)
1324       {
1325 #ifdef NS_IMPL_GNUSTEP
1326         g = unichars[i];
1327 #else
1328         g = glyphStorage->cglyphs[i];
1329         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1330         if (g > numGlyphs)
1331           g = 0xFFFF; /* hopefully unused... */
1332 #endif
1333         *glyphs = g;
1334       }
1336 #ifdef NS_IMPL_COCOA
1337     [allChars release];
1338 #endif
1339   }
1341   UNBLOCK_INPUT;
1342   xfree (unichars);
1346 /* Determine and cache metrics for corresponding glyph codes in given
1347    hi-byte block of 256. */
1348 static void
1349 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1351   unsigned int i, g;
1352   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1353   NSFont *sfont;
1354   struct font_metrics *metrics;
1356   if (NSFONT_TRACE)
1357     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1358             font_info, block);
1360 #ifdef NS_IMPL_GNUSTEP
1361   /* not implemented yet (as of startup 0.18), so punt */
1362   if (numGlyphs == 0)
1363     numGlyphs = 0x10000;
1364 #endif
1366  BLOCK_INPUT;
1367  sfont = [font_info->nsfont screenFont];
1369   font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1370   if (!(font_info->metrics[block]))
1371     abort ();
1373   metrics = font_info->metrics[block];
1374   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1375     {
1376       float w, lb, rb;
1377       NSRect r = [sfont boundingRectForGlyph: g];
1379       w = max ([sfont advancementForGlyph: g].width, 2.0);
1380       metrics->width = lrint (w);
1382       lb = r.origin.x;
1383       rb = r.size.width - w;
1384       if (lb < 0)
1385         metrics->lbearing = round (lb);
1386       if (font_info->ital)
1387         rb += 0.22 * font_info->height;
1388       metrics->rbearing = lrint (w + rb);
1390       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1391  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1392       metrics->ascent = r.size.height - metrics->descent;
1393 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1394     }
1395   UNBLOCK_INPUT;
1399 #ifdef NS_IMPL_COCOA
1400 /* helper for font glyph setup */
1401 @implementation EmacsGlyphStorage
1403 - init
1405   return [self initWithCapacity: 1024];
1408 - initWithCapacity: (unsigned long) c
1410   self = [super init];
1411   maxChar = 0;
1412   maxGlyph = 0;
1413   dict = [NSMutableDictionary new];
1414   cglyphs = xmalloc (c * sizeof (CGGlyph));
1415   return self;
1418 - (void) dealloc
1420   if (attrStr != nil)
1421     [attrStr release];
1422   [dict release];
1423   xfree (cglyphs);
1424   [super dealloc];
1427 - (void) setString: (NSString *)str font: (NSFont *)font
1429   [dict setObject: font forKey: NSFontAttributeName];
1430   if (attrStr != nil)
1431     [attrStr release];
1432   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1433   maxChar = [str length];
1434   maxGlyph = 0;
1437 /* NSGlyphStorage protocol */
1438 - (NSUInteger)layoutOptions
1440   return 0;
1443 - (NSAttributedString *)attributedString
1445   return attrStr;
1448 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1449         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1450         characterIndex: (NSUInteger)charIndex
1452   len = glyphIndex+length;
1453   for (i =glyphIndex; i<len; i++)
1454     cglyphs[i] = glyphs[i-glyphIndex];
1455   if (len > maxGlyph)
1456     maxGlyph = len;
1459 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1460         forGlyphAtIndex: (NSUInteger)glyphIndex
1462   return;
1465 @end
1466 #endif /* NS_IMPL_COCOA */
1469 /* Debugging */
1470 void
1471 ns_dump_glyphstring (struct glyph_string *s)
1473   int i;
1475   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1476 "overlap = %d, bg_filled = %d:",
1477            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1478            s->row->overlapping_p, s->background_filled_p);
1479   for (i =0; i<s->nchars; i++)
1480     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1481   fprintf (stderr, "\n");
1485 void
1486 syms_of_nsfont (void)
1488   nsfont_driver.type = Qns;
1489   register_font_driver (&nsfont_driver, NULL);
1490   DEFSYM (Qapple, "apple");
1491   DEFSYM (Qroman, "roman");
1492   DEFSYM (Qmedium, "medium");
1493   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1494                doc: /* Internal use: maps font registry to Unicode script. */);