(make_lispy_event): Remember last wheel direction.
[emacs.git] / src / nsfont.m
blob60e217fdc24cde2995766e1d20d2fe5a8c0a6cf7
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
23 /* This should be the first include, as it may set up #defines affecting
24    interpretation of even the system includes. */
25 #include "config.h"
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
31 #include "charset.h"
32 #include "frame.h"
33 #include "window.h"
34 #include "fontset.h"
35 #include "nsterm.h"
36 #include "frame.h"
37 #include "character.h"
38 #include "font.h"
40 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
41 #ifdef NS_IMPL_GNUSTEP
42 #import <AppKit/NSFontDescriptor.h>
43 #endif
45 #define NSFONT_TRACE 0
47 extern Lisp_Object Qns;
48 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
49 static Lisp_Object Vns_reg_to_script;
50 static Lisp_Object Qapple, Qroman, Qmedium;
51 extern Lisp_Object Qappend;
52 extern int ns_antialias_text;
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 = strdup (SDATA (SYMBOL_NAME (tem)));
104       NSString *family;
105       ns_unescape_name (tmp);
106       family = [NSString stringWithUTF8String: tmp];
107       free (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         fdesc = [fdesc fontDescriptorWithFamily: family];
157     return fdesc;
161 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
162 static Lisp_Object
163 ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
165     Lisp_Object font_entity = font_make_entity ();
166     /*   NSString *psName = [desc postscriptName]; */
167     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
168     unsigned int traits = [desc symbolicTraits];
169     char *escapedFamily;
171     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
172     if (family == nil)
173       family = [desc objectForKey: NSFontNameAttribute];
174     if (family == nil)
175       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
177     escapedFamily = strdup ([family UTF8String]);
178     ns_escape_name (escapedFamily);
180     ASET (font_entity, FONT_TYPE_INDEX, Qns);
181     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
182     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
183     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
184     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
186     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
187                     traits & NSFontBoldTrait ? Qbold : Qmedium);
188 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
189                     make_number (100 + 100
190                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
191     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
192                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
193 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
194                     make_number (100 + 100
195                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
196     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
197                     traits & NSFontCondensedTrait ? Qcondensed :
198                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
199 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
200                     make_number (100 + 100
201                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
203     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
204     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
205     ASET (font_entity, FONT_SPACING_INDEX,
206           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
207               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
209     ASET (font_entity, FONT_EXTRA_INDEX, extra);
210     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
212     if (NSFONT_TRACE)
213       {
214         fprintf (stderr, "created font_entity:\n    ");
215         debug_print (font_entity);
216       }
218     free (escapedFamily);
219     return font_entity;
223 /* Default font entity. */
224 static Lisp_Object
225 ns_fallback_entity ()
227   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
228       fontDescriptor], Qnil, NULL);
232 /* Utility: get width of a char c in screen font sfont */
233 static float
234 ns_char_width (NSFont *sfont, int c)
236     float w;
237     NSString *cstr = [NSString stringWithFormat: @"%c", c];
238 #ifdef NS_IMPL_COCOA
239     NSGlyph glyph = [sfont glyphWithName: cstr];
240     if (glyph)
241       {
242         float w = [sfont advancementForGlyph: glyph].width;
243         if (w >= 1.5)
244             return w;
245       }
246 #endif
247     w = [sfont widthOfString: cstr];
248     return max (w, 2.0);
252 /* Return whether set1 covers set2 to a reasonable extent given by pct.
253    We check, out of each 16 unicode char range containing chars in set2,
254    whether at least one character is present in set1.
255    This must be true for pct of the pairs to consider it covering. */
256 static BOOL
257 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
259     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
260     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
261     int i, off = 0, tot = 0;
263     for (i=0; i<4096; i++, bytes1++, bytes2++)
264         if (*bytes2)
265           {
266             tot++;
267             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
268                 off++;
269           }
270 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
271     return (float)off / tot < 1.0 - pct;
275 /* Convert :lang property to a script.  Use of :lang property by font backend
276    seems to be limited for now (2009/05) to ja, zh, and ko. */
277 static NSString
278 *ns_lang_to_script (Lisp_Object lang)
280     if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
281         return @"han";
282     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
283              have more characters. */
284     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
285         return @"han";
286     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
287         return @"hangul";
288     else
289         return @"";
293 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
294    everyone just use some standard unicode names for these?) */
295 static NSString
296 *ns_otf_to_script (Lisp_Object otf)
298     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
299     return CONSP (script)
300         ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
301         : @"";
305 /* Convert a font registry, such as  */
306 static NSString
307 *ns_registry_to_script (char *reg)
309     Lisp_Object script, r, rts = Vns_reg_to_script;
310     while CONSP (rts)
311       {
312         r = XCAR (XCAR (rts));
313         if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
314           {
315             script = XCDR (XCAR (rts));
316             return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
317           }
318         rts = XCDR (rts);
319       }
320     return  @"";
324 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
325    plus registry regular property, for something that can be mapped to a
326    unicode script.  Empty string returned if no script spec found. */
327 static NSString
328 *ns_get_req_script (Lisp_Object font_spec)
330     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
331     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
333     /* The extra-bundle properties have priority. */
334     for ( ; CONSP (extra); extra = XCDR (extra))
335       {
336         Lisp_Object tmp = XCAR (extra);
337         if (CONSP (tmp))
338           {
339             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
340             if (EQ (key, QCscript) && SYMBOLP (val))
341                 return [NSString stringWithUTF8String:
342                             SDATA (SYMBOL_NAME (val))];
343             if (EQ (key, QClang) && SYMBOLP (val))
344                 return ns_lang_to_script (val);
345             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
346                 return ns_otf_to_script (val);
347           }
348       }
350     /* If we get here, check the charset portion of the registry. */
351     if (! NILP (reg))
352       {
353         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
354            (which causes box rendering if we don't treat it like iso8858-1)
355            but also for ascii (which causes unnecessary font substitution). */
356 #if 0
357         if (EQ (reg, Qiso10646_1))
358           reg = Qiso8859_1;
359 #endif
360         return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
361       }
363     return @"";
367 /* This small function is static in fontset.c.  If it can be made public for
368    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
369 static void
370 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
372     if (EQ (XCAR (arg), val))
373       {
374         if (CONSP (range))
375           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
376         else
377           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
378       }
382 /* Use the unicode range information in Vchar_script_table to convert a script
383    name into an NSCharacterSet. */
384 static NSCharacterSet
385 *ns_script_to_charset (NSString *scriptName)
387     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
388     Lisp_Object script = intern ([scriptName UTF8String]);
389     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
391     if (! NILP (Fmemq (script, script_list)))
392       {
393         Lisp_Object ranges, range_list;
395         ranges = Fcons (script, Qnil);
396         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
397                         ranges);
398         range_list = Fnreverse (XCDR (ranges));
399         if (! NILP (range_list))
400           {
401             for (; CONSP (range_list); range_list = XCDR (range_list))
402               {
403                 int start = XINT (XCAR (XCAR (range_list)));
404                 int end = XINT (XCDR (XCAR (range_list)));
405                 if (NSFONT_TRACE)
406                     debug_print (XCAR (range_list));
407                 if (end < 0x10000)
408                     [charset addCharactersInRange:
409                         NSMakeRange (start, end-start)];
410               }
411           }
412       }
413     return charset;
417 /* Return an array of font families containing characters for the given
418    script, for the given coverage criterion, including at least LastResort.
419    Results are cached by script for faster access.
420    If none are found, we reduce the percentage and try again, until 5%.
421    This provides a font with at least some characters if such can be found.
422    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
423    (b) need approximate match as fonts covering full unicode ranges are rare. */
424 static NSSet
425 *ns_get_covering_families (NSString *script, float pct)
427     static NSMutableDictionary *scriptToFamilies = nil;
428     NSMutableSet *families;
430     if (NSFONT_TRACE)
431         NSLog(@"Request covering families for script: '%@'", script);
433     if (scriptToFamilies == nil)
434         scriptToFamilies = [[NSMutableDictionary alloc] init];
436     if ((families = [scriptToFamilies objectForKey: script]) == nil)
437       {
438         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
439         NSArray *allFamilies = [fontMgr availableFontFamilies];
441         if ([script length] == 0)
442             families = [NSMutableSet setWithArray: allFamilies];
443         else
444           {
445             NSCharacterSet *charset = ns_script_to_charset (script);
446             NSString *family;
447             families = [NSMutableSet setWithCapacity: 10];
448             while (1)
449               {
450                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
451                 while (family = [allFamiliesEnum nextObject])
452                   {
453                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
454                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
455                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
456                     if (fset == nil)
457                       fset = [NSCharacterSet characterSetWithRange:
458                                                NSMakeRange (0, 127)];
459                     if (ns_charset_covers(fset, charset, pct))
460                         [families addObject: family];
461                   }
462                 pct -= 0.2;
463                 if ([families count] > 0 || pct < 0.05)
464                     break;
465               }
466           }
467 #ifdef NS_IMPL_COCOA
468         if ([families count] == 0)
469             [families addObject: @"LastResort"];
470 #endif
471         [scriptToFamilies setObject: families forKey: script];
472       }
474     if (NSFONT_TRACE)
475         NSLog(@"    returning %d families", [families count]);
476     return families;
480 /* Implementation for list() and match().  List() can return nil, match()
481 must return something.  Strategy is to drop family name from attribute
482 matching set for match. */
483 static Lisp_Object
484 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
486     Lisp_Object tem, list = Qnil;
487     NSFontDescriptor *fdesc, *desc;
488     NSMutableSet *fkeys;
489     NSArray *matchingDescs;
490     NSEnumerator *dEnum;
491     NSString *family;
492     NSSet *cFamilies;
493     BOOL foundItal = NO;
495     if (NSFONT_TRACE)
496       {
497         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
498                  (isMatch ? "match" : "list"));
499         debug_print (font_spec);
500       }
502     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
504     fdesc = ns_spec_to_descriptor (font_spec);
505     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
506     if (isMatch)
507         [fkeys removeObject: NSFontFamilyAttribute];
509     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
510     if (NSFONT_TRACE)
511         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
512               [matchingDescs count]);
514     for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
515       {
516         if (![cFamilies containsObject:
517                  [desc objectForKey: NSFontFamilyAttribute]])
518             continue;
519         tem = ns_descriptor_to_entity (desc,
520                                          AREF (font_spec, FONT_EXTRA_INDEX),
521                                        NULL);
522         if (isMatch)
523           return tem;
524         list = Fcons (tem, list);
525         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
526             foundItal = YES;
527       }
529     /* Add synthItal member if needed. */
530     family = [fdesc objectForKey: NSFontFamilyAttribute];
531     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
532       {
533         NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
534             fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
535             fontDescriptorWithFamily: family];
536         list = Fcons (ns_descriptor_to_entity (sDesc,
537                                          AREF (font_spec, FONT_EXTRA_INDEX),
538                                          "synthItal"), list);
539       }
541     /* Return something if was a match and nothing found. */
542     if (isMatch)
543       return ns_fallback_entity ();
545     if (NSFONT_TRACE)
546         fprintf (stderr, "    Returning %d entities.\n", XINT (Flength (list)));
548     return list;
553 /* ==========================================================================
555     Font driver implementation
557    ========================================================================== */
560 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
561 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
562 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
563 static Lisp_Object nsfont_list_family (Lisp_Object frame);
564 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
565                                  int pixel_size);
566 static void nsfont_close (FRAME_PTR f, struct font *font);
567 static int nsfont_has_char (Lisp_Object entity, int c);
568 static unsigned int nsfont_encode_char (struct font *font, int c);
569 static int nsfont_text_extents (struct font *font, unsigned int *code,
570                                 int nglyphs, struct font_metrics *metrics);
571 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
572                         int with_background);
574 struct font_driver nsfont_driver =
575   {
576     0,                          /* Qns */
577     1,                          /* case sensitive */
578     nsfont_get_cache,
579     nsfont_list,
580     nsfont_match,
581     nsfont_list_family,
582     NULL,                       /*free_entity */
583     nsfont_open,
584     nsfont_close,
585     NULL,                       /* prepare_face */
586     NULL,                       /* done_face */
587     nsfont_has_char,
588     nsfont_encode_char,
589     nsfont_text_extents,
590     nsfont_draw,
591     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
592                  anchor_point, otf_capability, otf_driver,
593                  start_for_frame, end_for_frame, shape */
594   };
597 /* Return a cache of font-entities on FRAME.  The cache must be a
598    cons whose cdr part is the actual cache area.  */
599 static Lisp_Object
600 nsfont_get_cache (FRAME_PTR frame)
602   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
603   return (dpyinfo->name_list_element);
607 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
608    **list** of font-entities.  This and match () are sole APIs that allocate
609    font-entities.  Properties to be considered (2009/05/19) are:
610    regular: foundry, family, adstyle, registry
611    extended: script, lang, otf
612   "Extended" properties are not part of the vector but get stored as
613    lisp properties under FONT_EXTRA_INDEX.
615    The returned entities should have type set (to 'ns), plus the following:
616    foundry, family, adstyle, registry,
617    weight, slant, width, size (0 if scalable),
618    dpi, spacing, avgwidth (0 if scalable)  */
619 static Lisp_Object
620 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
622     return ns_findfonts (font_spec, NO);
626 /* Return a font entity most closely maching with FONT_SPEC on
627    FRAME.  The closeness is determined by the font backend, thus
628    `face-font-selection-order' is ignored here.
629    Properties to be considered are same as for list(). */
630 static Lisp_Object
631 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
633     return ns_findfonts(font_spec, YES);
637 /* List available families.  The value is a list of family names
638    (symbols). */
639 static Lisp_Object
640 nsfont_list_family (Lisp_Object frame)
642   Lisp_Object list = Qnil;
643   NSEnumerator *families =
644     [[[NSFontManager sharedFontManager] availableFontFamilies]
645       objectEnumerator];
646   NSString *family;
647   while (family = [families nextObject])
648       list = Fcons (intern ([family UTF8String]), list);
649   /* FIXME: escape the name? */
651   if (NSFONT_TRACE)
652     fprintf (stderr, "nsfont: list families returning %d entries\n",
653             XINT (Flength (list)));
655   return list;
659 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
660    scalable, open it with PIXEL_SIZE.  */
661 static Lisp_Object
662 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
664   BOOL synthItal;
665   unsigned int traits = 0;
666   struct nsfont_info *font_info;
667   struct font *font;
668   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
669   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
670   NSString *family;
671   NSFont *nsfont, *sfont;
672   Lisp_Object tem;
673   NSRect brect;
674   Lisp_Object font_object;
675   int i;
676   int fixLeopardBug;
677   static NSMutableDictionary *fontCache = nil;
678   NSNumber *cached;
680   /* 2008/03/08: The same font may end up being requested for different
681      entities, due to small differences in numeric values or other issues,
682      or for different copies of the same entity.  Therefore we cache to
683      avoid creating multiple struct font objects (with metrics cache, etc.)
684      for the same NSFont object. */
685   if (fontCache == nil)
686     fontCache = [[NSMutableDictionary alloc] init];
688   if (NSFONT_TRACE)
689     {
690       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
691       debug_print (font_entity);
692     }
694   if (pixel_size <= 0)
695     {
696       /* try to get it out of frame params */
697         Lisp_Object tem = get_frame_param (f, Qfontsize);
698         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
699     }
701   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
702   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
703                                        9);
704   family = ns_get_family (font_entity);
705   if (family == nil)
706     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
707   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
708      when setting family in ns_spec_to_descriptor(). */
709   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
710       traits |= NSBoldFontMask;
711   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
712       traits |= NSItalicFontMask;
714   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
715   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
716   nsfont = [fontMgr fontWithFamily: family
717                             traits: traits weight: fixLeopardBug
718                               size: pixel_size];
719   /* if didn't find, try synthetic italic */
720   if (nsfont == nil && synthItal)
721     {
722       nsfont = [fontMgr fontWithFamily: family
723                                 traits: traits & ~NSItalicFontMask
724                                 weight: fixLeopardBug size: pixel_size];
725     }
726 #ifdef NS_IMPL_COCOA
727   /* LastResort not really a family */
728   if (nsfont == nil && [@"LastResort" isEqualToString: family])
729       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
730 #endif
732   if (nsfont == nil)
733     {
734       message_with_string ("*** Warning: font in family '%s' not found",
735                           build_string ([family UTF8String]), 1);
736       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
737     }
739   if (NSFONT_TRACE)
740     NSLog (@"%@\n", nsfont);
742   /* Check the cache */
743   cached = [fontCache objectForKey: nsfont];
744   if (cached != nil && !synthItal)
745     {
746       if (NSFONT_TRACE)
747         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
748       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
749       XHASH (font_object) = [cached unsignedLongValue];
750       return font_object;
751     }
752   else
753     {
754       font_object = font_make_object (VECSIZE (struct nsfont_info),
755                                       font_entity, pixel_size);
756       if (!synthItal)
757         [fontCache setObject: [NSNumber numberWithUnsignedLong:
758                                           (unsigned long) XHASH (font_object)]
759                       forKey: nsfont];
760     }
762   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
763   font = (struct font *) font_info;
764   if (!font)
765     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
767   font_info->glyphs = (unsigned short **)
768     xmalloc (0x100 * sizeof (unsigned short *));
769   font_info->metrics = (struct font_metrics **)
770     xmalloc (0x100 * sizeof (struct font_metrics *));
771   if (!font_info->glyphs || !font_info->metrics)
772     return Qnil;
773   bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
774   bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
776   BLOCK_INPUT;
778   /* for metrics */
779   sfont = [nsfont screenFont];
780   if (sfont == nil)
781     sfont = nsfont;
783   /* non-metric backend font struct fields */
784   font = (struct font *) font_info;
785   font->pixel_size = [sfont pointSize];
786   font->driver = &nsfont_driver;
787   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
788   font->encoding_charset = -1;
789   font->repertory_charset = -1;
790   font->default_ascent = 0;
791   font->vertical_centering = 0;
792   font->baseline_offset = 0;
793   font->relative_compose = 0;
794   font->font_encoder = NULL;
796   font->props[FONT_FORMAT_INDEX] = Qns;
797   font->props[FONT_FILE_INDEX] = Qnil;
799   {
800     double expand, hshrink;
801     float full_height, min_height, hd;
802     const char *fontName = [[nsfont fontName] UTF8String];
803     int len = strlen (fontName);
805 #ifdef NS_IMPL_GNUSTEP
806     font_info->nsfont = sfont;
807 #else
808     font_info->nsfont = nsfont;
809 #endif
810     [font_info->nsfont retain];
812     /* set up ns_font (defined in nsgui.h) */
813     font_info->name = (char *)xmalloc (strlen (fontName) + 1);
814     bcopy (fontName, font_info->name, strlen (fontName) + 1);
815     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
816     font_info->ital =
817       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
819     /* Metrics etc.; some fonts return an unusually large max advance, so we
820        only use it for fonts that have wide characters. */
821     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
822       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
824     brect =  [sfont boundingRectForFont];
825     full_height = brect.size.height;
826     min_height = [sfont ascender] - [sfont descender];
827     hd = full_height - min_height;
829     /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
830     expand = 0.0;
831     hshrink = 1.0;
833     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
834     font_info->underwidth = [sfont underlineThickness];
835     font_info->size = font->pixel_size;
836     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
838     /* max bounds */
839     font_info->max_bounds.ascent =
840       lrint (hshrink * [sfont ascender] + expand * hd/2);
841     font_info->max_bounds.descent =
842       -lrint (hshrink* [sfont descender] - expand*hd/2);
843     font_info->height =
844       font_info->max_bounds.ascent + font_info->max_bounds.descent;
845     font_info->max_bounds.width = lrint (font_info->width);
846     font_info->max_bounds.lbearing = lrint (brect.origin.x);
847     font_info->max_bounds.rbearing =
848       lrint (brect.size.width - font_info->width);
850 #ifdef NS_IMPL_COCOA
851     /* set up synthItal and the CG font */
852     font_info->synthItal = synthItal;
853     {
854       ATSFontRef atsFont = ATSFontFindFromPostScriptName
855         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
857       if (atsFont == kATSFontRefUnspecified)
858         {
859           /* see if we can get it by dropping italic (then synthesizing) */
860           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
861               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
862                 fontName], kATSOptionFlagsDefault);
863           if (atsFont != kATSFontRefUnspecified)
864               font_info->synthItal = YES;
865           else
866             {
867               /* last resort fallback */
868               atsFont = ATSFontFindFromPostScriptName
869                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
870             }
871         }
872       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
873     }
874 #endif
876     /* set up metrics portion of font struct */
877     font->ascent = [sfont ascender];
878     font->descent = -[sfont descender];
879     font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
880     font->space_width = lrint (ns_char_width (sfont, ' '));
881     font->average_width = lrint (font_info->width);
882     font->max_width = lrint (font_info->max_bounds.width);
883     font->height = lrint (font_info->height);
884     font->underline_position = lrint (font_info->underpos);
885     font->underline_thickness = lrint (font_info->underwidth);
887     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
888     font->props[FONT_FULLNAME_INDEX] =
889       make_unibyte_string (font_info->name, strlen (font_info->name));
890   }
891   UNBLOCK_INPUT;
893   return font_object;
897 /* Close FONT on frame F. */
898 static void
899 nsfont_close (FRAME_PTR f, struct font *font)
901   struct nsfont_info *font_info = (struct nsfont_info *)font;
902   int i;
904   /* FIXME: this occurs apparently due to same failure to detect same font
905             that causes need for cache in nsfont_open () */
906   if (!font_info)
907       return;
909   for (i =0; i<0x100; i++)
910     {
911       xfree (font_info->glyphs[i]);
912       xfree (font_info->metrics[i]);
913     }
914   [font_info->nsfont release];
915 #ifdef NS_IMPL_COCOA
916   CGFontRelease (font_info->cgfont);
917 #endif
918   xfree (font_info->name);
919   xfree (font_info);
923 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
924    return 1.  If not, return 0.  If a font must be opened to check
925    it, return -1. */
926 static int
927 nsfont_has_char (Lisp_Object entity, int c)
929   return -1;
933 /* Return a glyph code of FONT for character C (Unicode code point).
934    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
935 static unsigned int
936 nsfont_encode_char (struct font *font, int c)
938   struct nsfont_info *font_info = (struct nsfont_info *)font;
939   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
940   unsigned short g;
942   if (c > 0xFFFF)
943     return FONT_INVALID_CODE;
945   /* did we already cache this block? */
946   if (!font_info->glyphs[high])
947     ns_uni_to_glyphs (font_info, high);
949   g = font_info->glyphs[high][low];
950   return g == 0xFFFF ? FONT_INVALID_CODE : g;
954 /* Perform the size computation of glyphs of FONT and fill in members
955    of METRICS.  The glyphs are specified by their glyph codes in
956    CODE (length NGLYPHS). */
957 static int
958 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
959                      struct font_metrics *metrics)
961   struct nsfont_info *font_info = (struct nsfont_info *)font;
962   struct font_metrics *pcm;
963   unsigned char high, low;
964   int totalWidth = 0;
965   int i;
967   bzero (metrics, sizeof (struct font_metrics));
969   for (i =0; i<nglyphs; i++)
970     {
971       /* get metrics for this glyph, filling cache if need be */
972       /* TODO: get metrics for whole string from an NSLayoutManager
973                (if not too slow) */
974       high = (code[i] & 0xFF00) >> 8;
975       low = code[i] & 0x00FF;
976       if (!font_info->metrics[high])
977         ns_glyph_metrics (font_info, high);
978       pcm = &(font_info->metrics[high][low]);
980       if (metrics->lbearing > totalWidth + pcm->lbearing)
981         metrics->lbearing = totalWidth + pcm->lbearing;
982       if (metrics->rbearing < totalWidth + pcm->rbearing)
983         metrics->rbearing = totalWidth + pcm->rbearing;
984       if (metrics->ascent < pcm->ascent)
985         metrics->ascent = pcm->ascent;
986       if (metrics->descent < pcm->descent)
987         metrics->descent = pcm->descent;
989       totalWidth += pcm->width;
990     }
992   metrics->width = totalWidth;
994   return totalWidth; /* not specified in doc, but xfont.c does it */
998 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
999    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
1000    is nonzero, fill the background in advance.  It is assured that
1001    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1002 static int
1003 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1004              int with_background)
1005 /* NOTE: focus and clip must be set
1006      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1008   static char cbuf[1024];
1009   char *c = cbuf;
1010 #ifdef NS_IMPL_GNUSTEP
1011   static float advances[1024];
1012   float *adv = advances;
1013 #else
1014   static CGSize advances[1024];
1015   CGSize *adv = advances;
1016 #endif
1017   struct face *face;
1018   NSRect r;
1019   struct nsfont_info *font = ns_tmp_font;
1020   NSColor *col, *bgCol;
1021   unsigned short *t = s->char2b;
1022   int i, len;
1023   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1024   int end = isComposite ? s->cmp_to : s->nchars;
1026   /* Select face based on input flags */
1027   switch (ns_tmp_flags)
1028     {
1029     case NS_DUMPGLYPH_CURSOR:
1030       face = s->face;
1031       break;
1032     case NS_DUMPGLYPH_MOUSEFACE:
1033       face = FACE_FROM_ID (s->f,
1034                            FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1035       if (!face)
1036         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1037       break;
1038     default:
1039       face = s->face;
1040     }
1042   r.origin.x = s->x;
1043   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1044     r.origin.x += abs (s->face->box_line_width);
1046   r.origin.y = s->y;
1047   r.size.height = FONT_HEIGHT (font);
1049   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1050      NS to render the string, it will come out differently from the individual
1051      character widths added up because of layout processing. */
1052   {
1053     XCharStruct *cs;
1054     int cwidth, twidth = 0;
1055     int hi, lo;
1056     /* FIXME: composition: no vertical displacement is considered. */
1057     t += s->cmp_from; /* advance into composition */
1058     for (i = s->cmp_from; i < end; i++, t++)
1059       {
1060         hi = (*t & 0xFF00) >> 8;
1061         lo = *t & 0x00FF;
1062         if (isComposite)
1063           {
1064             if (!s->first_glyph->u.cmp.automatic)
1065                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1066             else
1067               {
1068                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1069                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1070                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1071                     cwidth = LGLYPH_WIDTH (glyph);
1072                 else
1073                   {
1074                     cwidth = LGLYPH_WADJUST (glyph);
1075 #ifdef NS_IMPL_GNUSTEP
1076                     *(adv-1) += LGLYPH_XOFF (glyph);
1077 #else
1078                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1079 #endif
1080                   }
1081               }
1082           }
1083         else
1084           {
1085             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1086               ns_glyph_metrics (font, hi);
1087             cwidth = font->metrics[hi][lo].width;
1088           }
1089         twidth += cwidth;
1090 #ifdef NS_IMPL_GNUSTEP
1091         *adv++ = cwidth;
1092         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1093 #else
1094         (*adv++).width = cwidth;
1095 #endif
1096       }
1097     len = adv - advances;
1098     r.size.width = twidth;
1099     *c = 0;
1100   }
1102   /* fill background if requested */
1103   if (with_background && !isComposite)
1104     {
1105       NSRect br = r;
1106       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1107       int mbox_line_width = max (s->face->box_line_width, 0);
1109       if (s->row->full_width_p)
1110         {
1111           if (br.origin.x <= fibw + 1 + mbox_line_width)
1112             {
1113               br.size.width += br.origin.x - mbox_line_width;
1114               br.origin.x = mbox_line_width;
1115             }
1116           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1117                 <= fibw+1)
1118             br.size.width += fibw;
1119         }
1120       if (s->face->box == FACE_NO_BOX)
1121         {
1122           /* expand unboxed top row over internal border */
1123           if (br.origin.y <= fibw + 1 + mbox_line_width)
1124             {
1125               br.size.height += br.origin.y;
1126               br.origin.y = 0;
1127             }
1128         }
1129       else
1130         {
1131           int correction = abs (s->face->box_line_width)+1;
1132           br.origin.y += correction;
1133           br.size.height -= 2*correction;
1134           br.origin.x += correction;
1135           br.size.width -= 2*correction;
1136         }
1138       if (!s->face->stipple)
1139         [(NS_FACE_BACKGROUND (face) != 0
1140           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1141           : FRAME_BACKGROUND_COLOR (s->f)) set];
1142       else
1143         {
1144           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1145           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1146         }
1147       NSRectFill (br);
1148     }
1151   /* set up for character rendering */
1152   r.origin.y += font->voffset + (s->height - font->height)/2;
1154   col = (NS_FACE_FOREGROUND (face) != 0
1155          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1156          : FRAME_FOREGROUND_COLOR (s->f));
1157   /* FIXME: find another way to pass this */
1158   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1159            : (NS_FACE_BACKGROUND (face) != 0
1160               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1161               : FRAME_BACKGROUND_COLOR (s->f)));
1163   /* render under GNUstep using DPS */
1164 #ifdef NS_IMPL_GNUSTEP
1165   {
1166     NSGraphicsContext *context = GSCurrentContext ();
1168     DPSgsave (context);
1169     [font->nsfont set];
1171     /* do erase if "foreground" mode */
1172     if (bgCol != nil)
1173       {
1174         [bgCol set];
1175         DPSmoveto (context, r.origin.x, r.origin.y);
1176 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1177         DPSxshow (context, cbuf, advances, len);
1178         DPSstroke (context);
1179         [col set];
1180 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1181       }
1183     /* do underline */
1184     if (face->underline_p)
1185       {
1186         if (face->underline_color != 0)
1187           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1188         else
1189           [col set];
1190         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1191         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1192         if (face->underline_color != 0)
1193           [col set];
1194       }
1195     else
1196       [col set];
1198     /* draw with DPSxshow () */
1199     DPSmoveto (context, r.origin.x, r.origin.y);
1200     DPSxshow (context, cbuf, advances, len);
1201     DPSstroke (context);
1203     DPSgrestore (context);
1204     return to-from;
1205   }
1207 #else  /* NS_IMPL_COCOA */
1208   {
1209     CGContextRef gcontext =
1210       [[NSGraphicsContext currentContext] graphicsPort];
1211     static CGAffineTransform fliptf;
1212     static BOOL firstTime = YES;
1214     if (firstTime)
1215       {
1216         firstTime = NO;
1217         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1218       }
1220     CGContextSaveGState (gcontext);
1222     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1224     CGContextSetFont (gcontext, font->cgfont);
1225     CGContextSetFontSize (gcontext, font->size);
1226     if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1227       CGContextSetShouldAntialias (gcontext, 0);
1228     else
1229       CGContextSetShouldAntialias (gcontext, 1);
1231     CGContextSetTextMatrix (gcontext, fliptf);
1233     if (bgCol != nil)
1234       {
1235         /* foreground drawing; erase first to avoid overstrike */
1236         [bgCol set];
1237         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1238         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1239         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1240         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1241       }
1243     if (face->underline_p)
1244       {
1245         if (face->underline_color != 0)
1246           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1247         else
1248           [col set];
1249         CGContextBeginPath (gcontext);
1250         CGContextMoveToPoint (gcontext,
1251                               r.origin.x, r.origin.y + font->underpos);
1252         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1253                                 r.origin.y + font->underpos);
1254         CGContextStrokePath (gcontext);
1255         if (face->underline_color != 0)
1256           [col set];
1257       }
1258     else
1259       [col set];
1261     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1262     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1263                                     advances, len);
1265     if (face->overstrike)
1266       {
1267         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1268         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1269                                         advances, len);
1270       }
1272     CGContextRestoreGState (gcontext);
1273     return;
1274   }
1275 #endif  /* NS_IMPL_COCOA */
1281 /* ==========================================================================
1283     Font glyph and metrics caching functions
1285    ========================================================================== */
1287 /* Find and cache corresponding glyph codes for unicode values in given
1288    hi-byte block of 256. */
1289 static void
1290 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1292 #ifdef NS_IMPL_COCOA
1293   static EmacsGlyphStorage *glyphStorage;
1294   static char firstTime = 1;
1295 #endif
1296   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1297   unsigned int i, g, idx;
1298   unsigned short *glyphs;
1300   if (NSFONT_TRACE)
1301     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1302             font_info, block);
1304  BLOCK_INPUT;
1306 #ifdef NS_IMPL_COCOA
1307   if (firstTime)
1308     {
1309       firstTime = 0;
1310       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1311     }
1312 #endif
1314   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1315   if (!unichars || !(font_info->glyphs[block]))
1316     abort ();
1318   /* create a string containing all unicode characters in this block */
1319   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1320     if (idx < 0xD800 || idx > 0xDFFF)
1321       unichars[i] = idx;
1322     else
1323       unichars[i] = 0xFEFF;
1324   unichars[0x100] = 0;
1326   {
1327 #ifdef NS_IMPL_COCOA
1328     NSString *allChars = [[NSString alloc]
1329                                initWithCharactersNoCopy: unichars
1330                                                  length: 0x100
1331                                            freeWhenDone: NO];
1332     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1333     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1334     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1335     unsigned int gInd =0, cInd =0;
1337     [glyphStorage setString: allChars font: font_info->nsfont];
1338     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1339                         desiredNumberOfCharacters: glyphStorage->maxChar
1340                                        glyphIndex: &gInd characterIndex: &cInd];
1341 #endif
1342     glyphs = font_info->glyphs[block];
1343     for (i =0; i<0x100; i++, glyphs++)
1344       {
1345 #ifdef NS_IMPL_GNUSTEP
1346         g = unichars[i];
1347 #else
1348         g = glyphStorage->cglyphs[i];
1349         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1350         if (g > numGlyphs)
1351           g = 0xFFFF; /* hopefully unused... */
1352 #endif
1353         *glyphs = g;
1354       }
1356 #ifdef NS_IMPL_COCOA
1357     [allChars release];
1358 #endif
1359   }
1361   UNBLOCK_INPUT;
1362   xfree (unichars);
1366 /* Determine and cache metrics for corresponding glyph codes in given
1367    hi-byte block of 256. */
1368 static void
1369 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1371   unsigned int i, g;
1372   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1373   NSFont *sfont;
1374   struct font_metrics *metrics;
1376   if (NSFONT_TRACE)
1377     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1378             font_info, block);
1380 #ifdef NS_IMPL_GNUSTEP
1381   /* not implemented yet (as of startup 0.18), so punt */
1382   if (numGlyphs == 0)
1383     numGlyphs = 0x10000;
1384 #endif
1386  BLOCK_INPUT;
1387  sfont = [font_info->nsfont screenFont];
1389   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1390   bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1391   if (!(font_info->metrics[block]))
1392     abort ();
1394   metrics = font_info->metrics[block];
1395   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1396     {
1397       float w, lb, rb;
1398       NSRect r = [sfont boundingRectForGlyph: g];
1400       w = max ([sfont advancementForGlyph: g].width, 2.0);
1401       metrics->width = lrint (w);
1403       lb = r.origin.x;
1404       rb = r.size.width - w;
1405       if (lb < 0)
1406         metrics->lbearing = round (lb);
1407       if (font_info->ital)
1408         rb += 0.22 * font_info->height;
1409       metrics->rbearing = lrint (w + rb);
1411       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1412  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1413       metrics->ascent = r.size.height - metrics->descent;
1414 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1415     }
1416   UNBLOCK_INPUT;
1420 #ifdef NS_IMPL_COCOA
1421 /* helper for font glyph setup */
1422 @implementation EmacsGlyphStorage
1424 - init
1426   return [self initWithCapacity: 1024];
1429 - initWithCapacity: (unsigned long) c
1431   self = [super init];
1432   maxChar = 0;
1433   maxGlyph = 0;
1434   dict = [NSMutableDictionary new];
1435   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1436   return self;
1439 - (void) dealloc
1441   if (attrStr != nil)
1442     [attrStr release];
1443   [dict release];
1444   xfree (cglyphs);
1445   [super dealloc];
1448 - (void) setString: (NSString *)str font: (NSFont *)font
1450   [dict setObject: font forKey: NSFontAttributeName];
1451   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1452   maxChar = [str length];
1453   maxGlyph = 0;
1456 /* NSGlyphStorage protocol */
1457 - (unsigned int)layoutOptions
1459   return 0;
1462 - (NSAttributedString *)attributedString
1464   return attrStr;
1467 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1468         forStartingGlyphAtIndex: (unsigned int)glyphIndex
1469         characterIndex: (unsigned int)charIndex
1471   len = glyphIndex+length;
1472   for (i =glyphIndex; i<len; i++)
1473     cglyphs[i] = glyphs[i-glyphIndex];
1474   if (len > maxGlyph)
1475     maxGlyph = len;
1478 - (void)setIntAttribute: (int)attributeTag value: (int)val
1479         forGlyphAtIndex: (unsigned)glyphIndex
1481   return;
1484 @end
1485 #endif /* NS_IMPL_COCOA */
1488 /* Debugging */
1489 void
1490 ns_dump_glyphstring (struct glyph_string *s)
1492   int i;
1494   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1495 "overlap = %d, bg_filled = %d:",
1496            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1497            s->row->overlapping_p, s->background_filled_p);
1498   for (i =0; i<s->nchars; i++)
1499     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1500   fprintf (stderr, "\n");
1504 void
1505 syms_of_nsfont ()
1507   nsfont_driver.type = Qns;
1508   register_font_driver (&nsfont_driver, NULL);
1509   DEFSYM (Qapple, "apple");
1510   DEFSYM (Qroman, "roman");
1511   DEFSYM (Qmedium, "medium");
1512   DEFVAR_LISP ("ns-reg-to-script", &Vns_reg_to_script,
1513                doc: /* Internal use: maps font registry to unicode script. */);
1516 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae