Merge chages made in Gnus trunk.
[emacs.git] / src / nsfont.m
blob03b6d56ef092c509c85edbb49b2af766ff0d7401
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, 2010, 2011 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 = 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,
164                          Lisp_Object extra,
165                          const char *style)
167     Lisp_Object font_entity = font_make_entity ();
168     /*   NSString *psName = [desc postscriptName]; */
169     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
170     unsigned int traits = [desc symbolicTraits];
171     char *escapedFamily;
173     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
174     if (family == nil)
175       family = [desc objectForKey: NSFontNameAttribute];
176     if (family == nil)
177       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
179     escapedFamily = strdup ([family UTF8String]);
180     ns_escape_name (escapedFamily);
182     ASET (font_entity, FONT_TYPE_INDEX, Qns);
183     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
184     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
185     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
186     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
188     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
189                     traits & NSFontBoldTrait ? Qbold : Qmedium);
190 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
191                     make_number (100 + 100
192                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
193     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
194                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
195 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
196                     make_number (100 + 100
197                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
198     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
199                     traits & NSFontCondensedTrait ? Qcondensed :
200                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
201 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
202                     make_number (100 + 100
203                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
205     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
206     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
207     ASET (font_entity, FONT_SPACING_INDEX,
208           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
209               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
211     ASET (font_entity, FONT_EXTRA_INDEX, extra);
212     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
214     if (NSFONT_TRACE)
215       {
216         fprintf (stderr, "created font_entity:\n    ");
217         debug_print (font_entity);
218       }
220     free (escapedFamily);
221     return font_entity;
225 /* Default font entity. */
226 static Lisp_Object
227 ns_fallback_entity (void)
229   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
230       fontDescriptor], Qnil, NULL);
234 /* Utility: get width of a char c in screen font sfont */
235 static float
236 ns_char_width (NSFont *sfont, int c)
238     float w;
239     NSString *cstr = [NSString stringWithFormat: @"%c", c];
240 #ifdef NS_IMPL_COCOA
241     NSGlyph glyph = [sfont glyphWithName: cstr];
242     if (glyph)
243       {
244         float w = [sfont advancementForGlyph: glyph].width;
245         if (w >= 1.5)
246             return w;
247       }
248 #endif
249     {
250       NSDictionary *attrsDictionary =
251         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
252       w = [cstr sizeWithAttributes: attrsDictionary].width;
253     }
254     return max (w, 2.0);
258 /* Return whether set1 covers set2 to a reasonable extent given by pct.
259    We check, out of each 16 unicode char range containing chars in set2,
260    whether at least one character is present in set1.
261    This must be true for pct of the pairs to consider it covering. */
262 static BOOL
263 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
265     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
266     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
267     int i, off = 0, tot = 0;
269     for (i=0; i<4096; i++, bytes1++, bytes2++)
270         if (*bytes2)
271           {
272             tot++;
273             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
274                 off++;
275           }
276 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
277     return (float)off / tot < 1.0 - pct;
281 /* Convert :lang property to a script.  Use of :lang property by font backend
282    seems to be limited for now (2009/05) to ja, zh, and ko. */
283 static NSString
284 *ns_lang_to_script (Lisp_Object lang)
286     if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
287         return @"han";
288     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
289              have more characters. */
290     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
291         return @"han";
292     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
293         return @"hangul";
294     else
295         return @"";
299 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
300    everyone just use some standard unicode names for these?) */
301 static NSString
302 *ns_otf_to_script (Lisp_Object otf)
304     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
305     return CONSP (script)
306         ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
307         : @"";
311 /* Convert a font registry, such as  */
312 static NSString
313 *ns_registry_to_script (char *reg)
315     Lisp_Object script, r, rts = Vns_reg_to_script;
316     while CONSP (rts)
317       {
318         r = XCAR (XCAR (rts));
319         if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
320           {
321             script = XCDR (XCAR (rts));
322             return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
323           }
324         rts = XCDR (rts);
325       }
326     return  @"";
330 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
331    plus registry regular property, for something that can be mapped to a
332    unicode script.  Empty string returned if no script spec found. */
333 static NSString
334 *ns_get_req_script (Lisp_Object font_spec)
336     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
337     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
339     /* The extra-bundle properties have priority. */
340     for ( ; CONSP (extra); extra = XCDR (extra))
341       {
342         Lisp_Object tmp = XCAR (extra);
343         if (CONSP (tmp))
344           {
345             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
346             if (EQ (key, QCscript) && SYMBOLP (val))
347                 return [NSString stringWithUTF8String:
348                             SDATA (SYMBOL_NAME (val))];
349             if (EQ (key, QClang) && SYMBOLP (val))
350                 return ns_lang_to_script (val);
351             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
352                 return ns_otf_to_script (val);
353           }
354       }
356     /* If we get here, check the charset portion of the registry. */
357     if (! NILP (reg))
358       {
359         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
360            (which causes box rendering if we don't treat it like iso8858-1)
361            but also for ascii (which causes unnecessary font substitution). */
362 #if 0
363         if (EQ (reg, Qiso10646_1))
364           reg = Qiso8859_1;
365 #endif
366         return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
367       }
369     return @"";
373 /* This small function is static in fontset.c.  If it can be made public for
374    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
375 static void
376 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
378     if (EQ (XCAR (arg), val))
379       {
380         if (CONSP (range))
381           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
382         else
383           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
384       }
388 /* Use the unicode range information in Vchar_script_table to convert a script
389    name into an NSCharacterSet. */
390 static NSCharacterSet
391 *ns_script_to_charset (NSString *scriptName)
393     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
394     Lisp_Object script = intern ([scriptName UTF8String]);
395     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
397     if (! NILP (Fmemq (script, script_list)))
398       {
399         Lisp_Object ranges, range_list;
401         ranges = Fcons (script, Qnil);
402         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
403                         ranges);
404         range_list = Fnreverse (XCDR (ranges));
405         if (! NILP (range_list))
406           {
407             for (; CONSP (range_list); range_list = XCDR (range_list))
408               {
409                 int start = XINT (XCAR (XCAR (range_list)));
410                 int end = XINT (XCDR (XCAR (range_list)));
411                 if (NSFONT_TRACE)
412                     debug_print (XCAR (range_list));
413                 if (end < 0x10000)
414                     [charset addCharactersInRange:
415                         NSMakeRange (start, end-start)];
416               }
417           }
418       }
419     return charset;
423 /* Return an array of font families containing characters for the given
424    script, for the given coverage criterion, including at least LastResort.
425    Results are cached by script for faster access.
426    If none are found, we reduce the percentage and try again, until 5%.
427    This provides a font with at least some characters if such can be found.
428    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
429    (b) need approximate match as fonts covering full unicode ranges are rare. */
430 static NSSet
431 *ns_get_covering_families (NSString *script, float pct)
433     static NSMutableDictionary *scriptToFamilies = nil;
434     NSMutableSet *families;
436     if (NSFONT_TRACE)
437         NSLog(@"Request covering families for script: '%@'", script);
439     if (scriptToFamilies == nil)
440         scriptToFamilies = [[NSMutableDictionary alloc] init];
442     if ((families = [scriptToFamilies objectForKey: script]) == nil)
443       {
444         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
445         NSArray *allFamilies = [fontMgr availableFontFamilies];
447         if ([script length] == 0)
448             families = [NSMutableSet setWithArray: allFamilies];
449         else
450           {
451             NSCharacterSet *charset = ns_script_to_charset (script);
452             NSString *family;
453             families = [NSMutableSet setWithCapacity: 10];
454             while (1)
455               {
456                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
457                 while (family = [allFamiliesEnum nextObject])
458                   {
459                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
460                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
461                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
462                     if (fset == nil)
463                       fset = [NSCharacterSet characterSetWithRange:
464                                                NSMakeRange (0, 127)];
465                     if (ns_charset_covers(fset, charset, pct))
466                         [families addObject: family];
467                   }
468                 pct -= 0.2;
469                 if ([families count] > 0 || pct < 0.05)
470                     break;
471               }
472           }
473 #ifdef NS_IMPL_COCOA
474         if ([families count] == 0)
475             [families addObject: @"LastResort"];
476 #endif
477         [scriptToFamilies setObject: families forKey: script];
478       }
480     if (NSFONT_TRACE)
481         NSLog(@"    returning %d families", [families count]);
482     return families;
486 /* Implementation for list() and match().  List() can return nil, match()
487 must return something.  Strategy is to drop family name from attribute
488 matching set for match. */
489 static Lisp_Object
490 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
492     Lisp_Object tem, list = Qnil;
493     NSFontDescriptor *fdesc, *desc;
494     NSMutableSet *fkeys;
495     NSArray *matchingDescs;
496     NSEnumerator *dEnum;
497     NSString *family;
498     NSSet *cFamilies;
499     BOOL foundItal = NO;
501     if (NSFONT_TRACE)
502       {
503         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
504                  (isMatch ? "match" : "list"));
505         debug_print (font_spec);
506       }
508     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
510     fdesc = ns_spec_to_descriptor (font_spec);
511     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
512     if (isMatch)
513         [fkeys removeObject: NSFontFamilyAttribute];
515     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
516     if (NSFONT_TRACE)
517         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
518               [matchingDescs count]);
520     for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
521       {
522         if (![cFamilies containsObject:
523                  [desc objectForKey: NSFontFamilyAttribute]])
524             continue;
525         tem = ns_descriptor_to_entity (desc,
526                                          AREF (font_spec, FONT_EXTRA_INDEX),
527                                        NULL);
528         if (isMatch)
529           return tem;
530         list = Fcons (tem, list);
531         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
532             foundItal = YES;
533       }
535     /* Add synthItal member if needed. */
536     family = [fdesc objectForKey: NSFontFamilyAttribute];
537     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
538       {
539         NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
540             fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
541             fontDescriptorWithFamily: family];
542         list = Fcons (ns_descriptor_to_entity (sDesc,
543                                          AREF (font_spec, FONT_EXTRA_INDEX),
544                                          "synthItal"), list);
545       }
547     /* Return something if was a match and nothing found. */
548     if (isMatch)
549       return ns_fallback_entity ();
551     if (NSFONT_TRACE)
552         fprintf (stderr, "    Returning %ld entities.\n",
553                  (long) XINT (Flength (list)));
555     return list;
560 /* ==========================================================================
562     Font driver implementation
564    ========================================================================== */
567 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
568 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
569 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
570 static Lisp_Object nsfont_list_family (Lisp_Object frame);
571 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
572                                  int pixel_size);
573 static void nsfont_close (FRAME_PTR f, struct font *font);
574 static int nsfont_has_char (Lisp_Object entity, int c);
575 static unsigned int nsfont_encode_char (struct font *font, int c);
576 static int nsfont_text_extents (struct font *font, unsigned int *code,
577                                 int nglyphs, struct font_metrics *metrics);
578 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
579                         int with_background);
581 struct font_driver nsfont_driver =
582   {
583     0,                          /* Qns */
584     1,                          /* case sensitive */
585     nsfont_get_cache,
586     nsfont_list,
587     nsfont_match,
588     nsfont_list_family,
589     NULL,                       /*free_entity */
590     nsfont_open,
591     nsfont_close,
592     NULL,                       /* prepare_face */
593     NULL,                       /* done_face */
594     nsfont_has_char,
595     nsfont_encode_char,
596     nsfont_text_extents,
597     nsfont_draw,
598     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
599                  anchor_point, otf_capability, otf_driver,
600                  start_for_frame, end_for_frame, shape */
601   };
604 /* Return a cache of font-entities on FRAME.  The cache must be a
605    cons whose cdr part is the actual cache area.  */
606 static Lisp_Object
607 nsfont_get_cache (FRAME_PTR frame)
609   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
610   return (dpyinfo->name_list_element);
614 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
615    **list** of font-entities.  This and match () are sole APIs that allocate
616    font-entities.  Properties to be considered (2009/05/19) are:
617    regular: foundry, family, adstyle, registry
618    extended: script, lang, otf
619   "Extended" properties are not part of the vector but get stored as
620    lisp properties under FONT_EXTRA_INDEX.
622    The returned entities should have type set (to 'ns), plus the following:
623    foundry, family, adstyle, registry,
624    weight, slant, width, size (0 if scalable),
625    dpi, spacing, avgwidth (0 if scalable)  */
626 static Lisp_Object
627 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
629     return ns_findfonts (font_spec, NO);
633 /* Return a font entity most closely maching with FONT_SPEC on
634    FRAME.  The closeness is determined by the font backend, thus
635    `face-font-selection-order' is ignored here.
636    Properties to be considered are same as for list(). */
637 static Lisp_Object
638 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
640     return ns_findfonts(font_spec, YES);
644 /* List available families.  The value is a list of family names
645    (symbols). */
646 static Lisp_Object
647 nsfont_list_family (Lisp_Object frame)
649   Lisp_Object list = Qnil;
650   NSEnumerator *families =
651     [[[NSFontManager sharedFontManager] availableFontFamilies]
652       objectEnumerator];
653   NSString *family;
654   while (family = [families nextObject])
655       list = Fcons (intern ([family UTF8String]), list);
656   /* FIXME: escape the name? */
658   if (NSFONT_TRACE)
659     fprintf (stderr, "nsfont: list families returning %ld entries\n",
660             (long) XINT (Flength (list)));
662   return list;
666 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
667    scalable, open it with PIXEL_SIZE.  */
668 static Lisp_Object
669 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
671   BOOL synthItal;
672   unsigned int traits = 0;
673   struct nsfont_info *font_info;
674   struct font *font;
675   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
676   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
677   NSString *family;
678   NSFont *nsfont, *sfont;
679   Lisp_Object tem;
680   NSRect brect;
681   Lisp_Object font_object;
682   int i;
683   int fixLeopardBug;
684   static NSMutableDictionary *fontCache = nil;
685   NSNumber *cached;
687   /* 2008/03/08: The same font may end up being requested for different
688      entities, due to small differences in numeric values or other issues,
689      or for different copies of the same entity.  Therefore we cache to
690      avoid creating multiple struct font objects (with metrics cache, etc.)
691      for the same NSFont object. */
692   if (fontCache == nil)
693     fontCache = [[NSMutableDictionary alloc] init];
695   if (NSFONT_TRACE)
696     {
697       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
698       debug_print (font_entity);
699     }
701   if (pixel_size <= 0)
702     {
703       /* try to get it out of frame params */
704         Lisp_Object tem = get_frame_param (f, Qfontsize);
705         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
706     }
708   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
709   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
710                                        9);
711   family = ns_get_family (font_entity);
712   if (family == nil)
713     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
714   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
715      when setting family in ns_spec_to_descriptor(). */
716   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
717       traits |= NSBoldFontMask;
718   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
719       traits |= NSItalicFontMask;
721   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
722   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
723   nsfont = [fontMgr fontWithFamily: family
724                             traits: traits weight: fixLeopardBug
725                               size: pixel_size];
726   /* if didn't find, try synthetic italic */
727   if (nsfont == nil && synthItal)
728     {
729       nsfont = [fontMgr fontWithFamily: family
730                                 traits: traits & ~NSItalicFontMask
731                                 weight: fixLeopardBug size: pixel_size];
732     }
733 #ifdef NS_IMPL_COCOA
734   /* LastResort not really a family */
735   if (nsfont == nil && [@"LastResort" isEqualToString: family])
736       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
737 #endif
739   if (nsfont == nil)
740     {
741       message_with_string ("*** Warning: font in family '%s' not found",
742                           build_string ([family UTF8String]), 1);
743       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
744     }
746   if (NSFONT_TRACE)
747     NSLog (@"%@\n", nsfont);
749   /* Check the cache */
750   cached = [fontCache objectForKey: nsfont];
751   if (cached != nil && !synthItal)
752     {
753       if (NSFONT_TRACE)
754         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
755       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
756       XHASH (font_object) = [cached unsignedLongValue];
757       return font_object;
758     }
759   else
760     {
761       font_object = font_make_object (VECSIZE (struct nsfont_info),
762                                       font_entity, pixel_size);
763       if (!synthItal)
764         [fontCache setObject: [NSNumber numberWithUnsignedLong:
765                                           (unsigned long) XHASH (font_object)]
766                       forKey: nsfont];
767     }
769   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
770   font = (struct font *) font_info;
771   if (!font)
772     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
774   font_info->glyphs = (unsigned short **)
775     xmalloc (0x100 * sizeof (unsigned short *));
776   font_info->metrics = (struct font_metrics **)
777     xmalloc (0x100 * sizeof (struct font_metrics *));
778   if (!font_info->glyphs || !font_info->metrics)
779     return Qnil;
780   memset (font_info->glyphs, 0, 0x100 * sizeof (unsigned short *));
781   memset (font_info->metrics, 0, 0x100 * sizeof (struct font_metrics *));
783   BLOCK_INPUT;
785   /* for metrics */
786   sfont = [nsfont screenFont];
787   if (sfont == nil)
788     sfont = nsfont;
790   /* non-metric backend font struct fields */
791   font = (struct font *) font_info;
792   font->pixel_size = [sfont pointSize];
793   font->driver = &nsfont_driver;
794   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
795   font->encoding_charset = -1;
796   font->repertory_charset = -1;
797   font->default_ascent = 0;
798   font->vertical_centering = 0;
799   font->baseline_offset = 0;
800   font->relative_compose = 0;
801   font->font_encoder = NULL;
803   font->props[FONT_FORMAT_INDEX] = Qns;
804   font->props[FONT_FILE_INDEX] = Qnil;
806   {
807     double expand, hshrink;
808     float full_height, min_height, hd;
809     const char *fontName = [[nsfont fontName] UTF8String];
810     int len = strlen (fontName);
812 #ifdef NS_IMPL_GNUSTEP
813     font_info->nsfont = sfont;
814 #else
815     font_info->nsfont = nsfont;
816 #endif
817     [font_info->nsfont retain];
819     /* set up ns_font (defined in nsgui.h) */
820     font_info->name = (char *)xmalloc (strlen (fontName)+1);
821     strcpy (font_info->name, fontName);
822     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
823     font_info->ital =
824       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
826     /* Metrics etc.; some fonts return an unusually large max advance, so we
827        only use it for fonts that have wide characters. */
828     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
829       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
831     brect =  [sfont boundingRectForFont];
832     full_height = brect.size.height;
833     min_height = [sfont ascender] - [sfont descender];
834     hd = full_height - min_height;
836     /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
837     expand = 0.0;
838     hshrink = 1.0;
840     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
841     font_info->underwidth = [sfont underlineThickness];
842     font_info->size = font->pixel_size;
843     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
845     /* max bounds */
846     font_info->max_bounds.ascent =
847       lrint (hshrink * [sfont ascender] + expand * hd/2);
848     /* [sfont descender] is usually negative.  Use floor to avoid
849        clipping descenders. */
850     font_info->max_bounds.descent =
851       -lrint (floor(hshrink* [sfont descender] - expand*hd/2));
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([sfont 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     XCharStruct *cs;
1062     int cwidth, twidth = 0;
1063     int hi, lo;
1064     /* FIXME: composition: no vertical displacement is considered. */
1065     t += s->cmp_from; /* advance into composition */
1066     for (i = s->cmp_from; i < end; i++, t++)
1067       {
1068         hi = (*t & 0xFF00) >> 8;
1069         lo = *t & 0x00FF;
1070         if (isComposite)
1071           {
1072             if (!s->first_glyph->u.cmp.automatic)
1073                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1074             else
1075               {
1076                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1077                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1078                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1079                     cwidth = LGLYPH_WIDTH (glyph);
1080                 else
1081                   {
1082                     cwidth = LGLYPH_WADJUST (glyph);
1083 #ifdef NS_IMPL_GNUSTEP
1084                     *(adv-1) += LGLYPH_XOFF (glyph);
1085 #else
1086                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1087 #endif
1088                   }
1089               }
1090           }
1091         else
1092           {
1093             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1094               ns_glyph_metrics (font, hi);
1095             cwidth = font->metrics[hi][lo].width;
1096           }
1097         twidth += cwidth;
1098 #ifdef NS_IMPL_GNUSTEP
1099         *adv++ = cwidth;
1100         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1101 #else
1102         (*adv++).width = cwidth;
1103 #endif
1104       }
1105     len = adv - advances;
1106     r.size.width = twidth;
1107     *c = 0;
1108   }
1110   /* fill background if requested */
1111   if (with_background && !isComposite)
1112     {
1113       NSRect br = r;
1114       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1115       int mbox_line_width = max (s->face->box_line_width, 0);
1117       if (s->row->full_width_p)
1118         {
1119           if (br.origin.x <= fibw + 1 + mbox_line_width)
1120             {
1121               br.size.width += br.origin.x - mbox_line_width;
1122               br.origin.x = mbox_line_width;
1123             }
1124           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1125                 <= fibw+1)
1126             br.size.width += fibw;
1127         }
1128       if (s->face->box == FACE_NO_BOX)
1129         {
1130           /* expand unboxed top row over internal border */
1131           if (br.origin.y <= fibw + 1 + mbox_line_width)
1132             {
1133               br.size.height += br.origin.y;
1134               br.origin.y = 0;
1135             }
1136         }
1137       else
1138         {
1139           int correction = abs (s->face->box_line_width)+1;
1140           br.origin.y += correction;
1141           br.size.height -= 2*correction;
1142           br.origin.x += correction;
1143           br.size.width -= 2*correction;
1144         }
1146       if (!s->face->stipple)
1147         [(NS_FACE_BACKGROUND (face) != 0
1148           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1149           : FRAME_BACKGROUND_COLOR (s->f)) set];
1150       else
1151         {
1152           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1153           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1154         }
1155       NSRectFill (br);
1156     }
1159   /* set up for character rendering */
1160   r.origin.y += font->voffset + (s->height - font->height)/2;
1162   col = (NS_FACE_FOREGROUND (face) != 0
1163          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1164          : FRAME_FOREGROUND_COLOR (s->f));
1165   /* FIXME: find another way to pass this */
1166   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1167            : (NS_FACE_BACKGROUND (face) != 0
1168               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1169               : FRAME_BACKGROUND_COLOR (s->f)));
1171   /* render under GNUstep using DPS */
1172 #ifdef NS_IMPL_GNUSTEP
1173   {
1174     NSGraphicsContext *context = GSCurrentContext ();
1176     DPSgsave (context);
1177     [font->nsfont set];
1179     /* do erase if "foreground" mode */
1180     if (bgCol != nil)
1181       {
1182         [bgCol set];
1183         DPSmoveto (context, r.origin.x, r.origin.y);
1184 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1185         DPSxshow (context, cbuf, advances, len);
1186         DPSstroke (context);
1187         [col set];
1188 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1189       }
1191     /* do underline */
1192     if (face->underline_p)
1193       {
1194         if (face->underline_color != 0)
1195           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1196         else
1197           [col set];
1198         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1199         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1200         if (face->underline_color != 0)
1201           [col set];
1202       }
1203     else
1204       [col set];
1206     /* draw with DPSxshow () */
1207     DPSmoveto (context, r.origin.x, r.origin.y);
1208     DPSxshow (context, cbuf, advances, len);
1209     DPSstroke (context);
1211     DPSgrestore (context);
1212   }
1214 #else  /* NS_IMPL_COCOA */
1215   {
1216     CGContextRef gcontext =
1217       [[NSGraphicsContext currentContext] graphicsPort];
1218     static CGAffineTransform fliptf;
1219     static BOOL firstTime = YES;
1221     if (firstTime)
1222       {
1223         firstTime = NO;
1224         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1225       }
1227     CGContextSaveGState (gcontext);
1229     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1231     CGContextSetFont (gcontext, font->cgfont);
1232     CGContextSetFontSize (gcontext, font->size);
1233     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1234       CGContextSetShouldAntialias (gcontext, 0);
1235     else
1236       CGContextSetShouldAntialias (gcontext, 1);
1238     CGContextSetTextMatrix (gcontext, fliptf);
1240     if (bgCol != nil)
1241       {
1242         /* foreground drawing; erase first to avoid overstrike */
1243         [bgCol set];
1244         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1245         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1246         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1247         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1248       }
1250     if (face->underline_p)
1251       {
1252         if (face->underline_color != 0)
1253           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1254         else
1255           [col set];
1256         CGContextBeginPath (gcontext);
1257         CGContextMoveToPoint (gcontext,
1258                               r.origin.x, r.origin.y + font->underpos);
1259         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1260                                 r.origin.y + font->underpos);
1261         CGContextStrokePath (gcontext);
1262         if (face->underline_color != 0)
1263           [col set];
1264       }
1265     else
1266       [col set];
1268     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1269     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1270                                     advances, len);
1272     if (face->overstrike)
1273       {
1274         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1275         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1276                                         advances, len);
1277       }
1279     CGContextRestoreGState (gcontext);
1280   }
1281 #endif  /* NS_IMPL_COCOA */
1282   return to-from;
1287 /* ==========================================================================
1289     Font glyph and metrics caching functions
1291    ========================================================================== */
1293 /* Find and cache corresponding glyph codes for unicode values in given
1294    hi-byte block of 256. */
1295 static void
1296 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1298 #ifdef NS_IMPL_COCOA
1299   static EmacsGlyphStorage *glyphStorage;
1300   static char firstTime = 1;
1301 #endif
1302   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1303   unsigned int i, g, idx;
1304   unsigned short *glyphs;
1306   if (NSFONT_TRACE)
1307     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1308             font_info, block);
1310  BLOCK_INPUT;
1312 #ifdef NS_IMPL_COCOA
1313   if (firstTime)
1314     {
1315       firstTime = 0;
1316       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1317     }
1318 #endif
1320   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1321   if (!unichars || !(font_info->glyphs[block]))
1322     abort ();
1324   /* create a string containing all unicode characters in this block */
1325   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1326     if (idx < 0xD800 || idx > 0xDFFF)
1327       unichars[i] = idx;
1328     else
1329       unichars[i] = 0xFEFF;
1330   unichars[0x100] = 0;
1332   {
1333 #ifdef NS_IMPL_COCOA
1334     NSString *allChars = [[NSString alloc]
1335                                initWithCharactersNoCopy: unichars
1336                                                  length: 0x100
1337                                            freeWhenDone: NO];
1338     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1339     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1340     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1341     NSUInteger gInd =0, cInd =0;
1343     [glyphStorage setString: allChars font: font_info->nsfont];
1344     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1345                         desiredNumberOfCharacters: glyphStorage->maxChar
1346                                        glyphIndex: &gInd characterIndex: &cInd];
1347 #endif
1348     glyphs = font_info->glyphs[block];
1349     for (i =0; i<0x100; i++, glyphs++)
1350       {
1351 #ifdef NS_IMPL_GNUSTEP
1352         g = unichars[i];
1353 #else
1354         g = glyphStorage->cglyphs[i];
1355         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1356         if (g > numGlyphs)
1357           g = 0xFFFF; /* hopefully unused... */
1358 #endif
1359         *glyphs = g;
1360       }
1362 #ifdef NS_IMPL_COCOA
1363     [allChars release];
1364 #endif
1365   }
1367   UNBLOCK_INPUT;
1368   xfree (unichars);
1372 /* Determine and cache metrics for corresponding glyph codes in given
1373    hi-byte block of 256. */
1374 static void
1375 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1377   unsigned int i, g;
1378   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1379   NSFont *sfont;
1380   struct font_metrics *metrics;
1382   if (NSFONT_TRACE)
1383     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1384             font_info, block);
1386 #ifdef NS_IMPL_GNUSTEP
1387   /* not implemented yet (as of startup 0.18), so punt */
1388   if (numGlyphs == 0)
1389     numGlyphs = 0x10000;
1390 #endif
1392  BLOCK_INPUT;
1393  sfont = [font_info->nsfont screenFont];
1395   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1396   memset (font_info->metrics[block], 0, 0x100 * sizeof (struct font_metrics));
1397   if (!(font_info->metrics[block]))
1398     abort ();
1400   metrics = font_info->metrics[block];
1401   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1402     {
1403       float w, lb, rb;
1404       NSRect r = [sfont boundingRectForGlyph: g];
1406       w = max ([sfont advancementForGlyph: g].width, 2.0);
1407       metrics->width = lrint (w);
1409       lb = r.origin.x;
1410       rb = r.size.width - w;
1411       if (lb < 0)
1412         metrics->lbearing = round (lb);
1413       if (font_info->ital)
1414         rb += 0.22 * font_info->height;
1415       metrics->rbearing = lrint (w + rb);
1417       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1418  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1419       metrics->ascent = r.size.height - metrics->descent;
1420 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1421     }
1422   UNBLOCK_INPUT;
1426 #ifdef NS_IMPL_COCOA
1427 /* helper for font glyph setup */
1428 @implementation EmacsGlyphStorage
1430 - init
1432   return [self initWithCapacity: 1024];
1435 - initWithCapacity: (unsigned long) c
1437   self = [super init];
1438   maxChar = 0;
1439   maxGlyph = 0;
1440   dict = [NSMutableDictionary new];
1441   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1442   return self;
1445 - (void) dealloc
1447   if (attrStr != nil)
1448     [attrStr release];
1449   [dict release];
1450   xfree (cglyphs);
1451   [super dealloc];
1454 - (void) setString: (NSString *)str font: (NSFont *)font
1456   [dict setObject: font forKey: NSFontAttributeName];
1457   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1458   maxChar = [str length];
1459   maxGlyph = 0;
1462 /* NSGlyphStorage protocol */
1463 - (NSUInteger)layoutOptions
1465   return 0;
1468 - (NSAttributedString *)attributedString
1470   return attrStr;
1473 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1474         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1475         characterIndex: (NSUInteger)charIndex
1477   len = glyphIndex+length;
1478   for (i =glyphIndex; i<len; i++)
1479     cglyphs[i] = glyphs[i-glyphIndex];
1480   if (len > maxGlyph)
1481     maxGlyph = len;
1484 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1485         forGlyphAtIndex: (NSUInteger)glyphIndex
1487   return;
1490 @end
1491 #endif /* NS_IMPL_COCOA */
1494 /* Debugging */
1495 void
1496 ns_dump_glyphstring (struct glyph_string *s)
1498   int i;
1500   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1501 "overlap = %d, bg_filled = %d:",
1502            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1503            s->row->overlapping_p, s->background_filled_p);
1504   for (i =0; i<s->nchars; i++)
1505     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1506   fprintf (stderr, "\n");
1510 void
1511 syms_of_nsfont (void)
1513   nsfont_driver.type = Qns;
1514   register_font_driver (&nsfont_driver, NULL);
1515   DEFSYM (Qapple, "apple");
1516   DEFSYM (Qroman, "roman");
1517   DEFSYM (Qmedium, "medium");
1518   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1519                doc: /* Internal use: maps font registry to unicode script. */);