* lisp/emacs-lisp/bytecomp.el (byte-compile-disable-print-circle): Obsolete.
[emacs.git] / src / nsfont.m
blob68cd19da70e1015d751d2a04468bc4accdbb1f66
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2    See font.h
3    Copyright (C) 2006-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     /* The values specified by fonts are not always exact. For
813      * example, a 6x8 font could specify that the descender is
814      * -2.00000405... (represented by 0xc000000220000000).  Without
815      * adjustment, the code below would round the descender to -3,
816      * resulting in a font that would be one pixel higher than
817      * intended. */
818     CGFloat adjusted_descender = [sfont descender] + 0.0001;
820 #ifdef NS_IMPL_GNUSTEP
821     font_info->nsfont = sfont;
822 #else
823     font_info->nsfont = nsfont;
824 #endif
825     [font_info->nsfont retain];
827     /* set up ns_font (defined in nsgui.h) */
828     font_info->name = (char *)xmalloc (strlen (fontName)+1);
829     strcpy (font_info->name, fontName);
830     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
831     font_info->ital =
832       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
834     /* Metrics etc.; some fonts return an unusually large max advance, so we
835        only use it for fonts that have wide characters. */
836     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
837       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
839     brect =  [sfont boundingRectForFont];
840     full_height = brect.size.height;
841     min_height = [sfont ascender] - adjusted_descender;
842     hd = full_height - min_height;
844     /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
845     expand = 0.0;
846     hshrink = 1.0;
848     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
849     font_info->underwidth = [sfont underlineThickness];
850     font_info->size = font->pixel_size;
851     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
853     /* max bounds */
854     font_info->max_bounds.ascent =
855       lrint (hshrink * [sfont ascender] + expand * hd/2);
856     /* Descender is usually negative.  Use floor to avoid
857        clipping descenders. */
858     font_info->max_bounds.descent =
859       -lrint (floor(hshrink* adjusted_descender - expand*hd/2));
860     font_info->height =
861       font_info->max_bounds.ascent + font_info->max_bounds.descent;
862     font_info->max_bounds.width = lrint (font_info->width);
863     font_info->max_bounds.lbearing = lrint (brect.origin.x);
864     font_info->max_bounds.rbearing =
865       lrint (brect.size.width - font_info->width);
867 #ifdef NS_IMPL_COCOA
868     /* set up synthItal and the CG font */
869     font_info->synthItal = synthItal;
870     {
871       ATSFontRef atsFont = ATSFontFindFromPostScriptName
872         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
874       if (atsFont == kATSFontRefUnspecified)
875         {
876           /* see if we can get it by dropping italic (then synthesizing) */
877           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
878               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
879                 fontName], kATSOptionFlagsDefault);
880           if (atsFont != kATSFontRefUnspecified)
881               font_info->synthItal = YES;
882           else
883             {
884               /* last resort fallback */
885               atsFont = ATSFontFindFromPostScriptName
886                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
887             }
888         }
889       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
890     }
891 #endif
893     /* set up metrics portion of font struct */
894     font->ascent = lrint([sfont ascender]);
895     font->descent = -lrint(floor(adjusted_descender));
896     font->min_width = ns_char_width(sfont, '|');
897     font->space_width = lrint (ns_char_width (sfont, ' '));
898     font->average_width = lrint (font_info->width);
899     font->max_width = lrint (font_info->max_bounds.width);
900     font->height = lrint (font_info->height);
901     font->underline_position = lrint (font_info->underpos);
902     font->underline_thickness = lrint (font_info->underwidth);
904     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
905     font->props[FONT_FULLNAME_INDEX] =
906       make_unibyte_string (font_info->name, strlen (font_info->name));
907   }
908   UNBLOCK_INPUT;
910   return font_object;
914 /* Close FONT on frame F. */
915 static void
916 nsfont_close (FRAME_PTR f, struct font *font)
918   struct nsfont_info *font_info = (struct nsfont_info *)font;
919   int i;
921   /* FIXME: this occurs apparently due to same failure to detect same font
922             that causes need for cache in nsfont_open () */
923   if (!font_info)
924       return;
926   for (i =0; i<0x100; i++)
927     {
928       xfree (font_info->glyphs[i]);
929       xfree (font_info->metrics[i]);
930     }
931   [font_info->nsfont release];
932 #ifdef NS_IMPL_COCOA
933   CGFontRelease (font_info->cgfont);
934 #endif
935   xfree (font_info->name);
936   xfree (font_info);
940 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
941    return 1.  If not, return 0.  If a font must be opened to check
942    it, return -1. */
943 static int
944 nsfont_has_char (Lisp_Object entity, int c)
946   return -1;
950 /* Return a glyph code of FONT for character C (Unicode code point).
951    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
952 static unsigned int
953 nsfont_encode_char (struct font *font, int c)
955   struct nsfont_info *font_info = (struct nsfont_info *)font;
956   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
957   unsigned short g;
959   if (c > 0xFFFF)
960     return FONT_INVALID_CODE;
962   /* did we already cache this block? */
963   if (!font_info->glyphs[high])
964     ns_uni_to_glyphs (font_info, high);
966   g = font_info->glyphs[high][low];
967   return g == 0xFFFF ? FONT_INVALID_CODE : g;
971 /* Perform the size computation of glyphs of FONT and fill in members
972    of METRICS.  The glyphs are specified by their glyph codes in
973    CODE (length NGLYPHS). */
974 static int
975 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
976                      struct font_metrics *metrics)
978   struct nsfont_info *font_info = (struct nsfont_info *)font;
979   struct font_metrics *pcm;
980   unsigned char high, low;
981   int totalWidth = 0;
982   int i;
984   memset (metrics, 0, sizeof (struct font_metrics));
986   for (i =0; i<nglyphs; i++)
987     {
988       /* get metrics for this glyph, filling cache if need be */
989       /* TODO: get metrics for whole string from an NSLayoutManager
990                (if not too slow) */
991       high = (code[i] & 0xFF00) >> 8;
992       low = code[i] & 0x00FF;
993       if (!font_info->metrics[high])
994         ns_glyph_metrics (font_info, high);
995       pcm = &(font_info->metrics[high][low]);
997       if (metrics->lbearing > totalWidth + pcm->lbearing)
998         metrics->lbearing = totalWidth + pcm->lbearing;
999       if (metrics->rbearing < totalWidth + pcm->rbearing)
1000         metrics->rbearing = totalWidth + pcm->rbearing;
1001       if (metrics->ascent < pcm->ascent)
1002         metrics->ascent = pcm->ascent;
1003       if (metrics->descent < pcm->descent)
1004         metrics->descent = pcm->descent;
1006       totalWidth += pcm->width;
1007     }
1009   metrics->width = totalWidth;
1011   return totalWidth; /* not specified in doc, but xfont.c does it */
1015 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1016    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
1017    is nonzero, fill the background in advance.  It is assured that
1018    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1019 static int
1020 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1021              int with_background)
1022 /* NOTE: focus and clip must be set
1023      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1025   static char cbuf[1024];
1026   char *c = cbuf;
1027 #ifdef NS_IMPL_GNUSTEP
1028   static float advances[1024];
1029   float *adv = advances;
1030 #else
1031   static CGSize advances[1024];
1032   CGSize *adv = advances;
1033 #endif
1034   struct face *face;
1035   NSRect r;
1036   struct nsfont_info *font = ns_tmp_font;
1037   NSColor *col, *bgCol;
1038   unsigned short *t = s->char2b;
1039   int i, len;
1040   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1041   int end = isComposite ? s->cmp_to : s->nchars;
1043   /* Select face based on input flags */
1044   switch (ns_tmp_flags)
1045     {
1046     case NS_DUMPGLYPH_CURSOR:
1047       face = s->face;
1048       break;
1049     case NS_DUMPGLYPH_MOUSEFACE:
1050       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1051       if (!face)
1052         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1053       break;
1054     default:
1055       face = s->face;
1056     }
1058   r.origin.x = s->x;
1059   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1060     r.origin.x += abs (s->face->box_line_width);
1062   r.origin.y = s->y;
1063   r.size.height = FONT_HEIGHT (font);
1065   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1066      NS to render the string, it will come out differently from the individual
1067      character widths added up because of layout processing. */
1068   {
1069     XCharStruct *cs;
1070     int cwidth, twidth = 0;
1071     int hi, lo;
1072     /* FIXME: composition: no vertical displacement is considered. */
1073     t += s->cmp_from; /* advance into composition */
1074     for (i = s->cmp_from; i < end; i++, t++)
1075       {
1076         hi = (*t & 0xFF00) >> 8;
1077         lo = *t & 0x00FF;
1078         if (isComposite)
1079           {
1080             if (!s->first_glyph->u.cmp.automatic)
1081                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1082             else
1083               {
1084                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1085                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1086                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1087                     cwidth = LGLYPH_WIDTH (glyph);
1088                 else
1089                   {
1090                     cwidth = LGLYPH_WADJUST (glyph);
1091 #ifdef NS_IMPL_GNUSTEP
1092                     *(adv-1) += LGLYPH_XOFF (glyph);
1093 #else
1094                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1095 #endif
1096                   }
1097               }
1098           }
1099         else
1100           {
1101             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1102               ns_glyph_metrics (font, hi);
1103             cwidth = font->metrics[hi][lo].width;
1104           }
1105         twidth += cwidth;
1106 #ifdef NS_IMPL_GNUSTEP
1107         *adv++ = cwidth;
1108         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1109 #else
1110         (*adv++).width = cwidth;
1111 #endif
1112       }
1113     len = adv - advances;
1114     r.size.width = twidth;
1115     *c = 0;
1116   }
1118   /* fill background if requested */
1119   if (with_background && !isComposite)
1120     {
1121       NSRect br = r;
1122       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1123       int mbox_line_width = max (s->face->box_line_width, 0);
1125       if (s->row->full_width_p)
1126         {
1127           if (br.origin.x <= fibw + 1 + mbox_line_width)
1128             {
1129               br.size.width += br.origin.x - mbox_line_width;
1130               br.origin.x = mbox_line_width;
1131             }
1132           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1133                 <= fibw+1)
1134             br.size.width += fibw;
1135         }
1136       if (s->face->box == FACE_NO_BOX)
1137         {
1138           /* expand unboxed top row over internal border */
1139           if (br.origin.y <= fibw + 1 + mbox_line_width)
1140             {
1141               br.size.height += br.origin.y;
1142               br.origin.y = 0;
1143             }
1144         }
1145       else
1146         {
1147           int correction = abs (s->face->box_line_width)+1;
1148           br.origin.y += correction;
1149           br.size.height -= 2*correction;
1150           br.origin.x += correction;
1151           br.size.width -= 2*correction;
1152         }
1154       if (!s->face->stipple)
1155         [(NS_FACE_BACKGROUND (face) != 0
1156           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1157           : FRAME_BACKGROUND_COLOR (s->f)) set];
1158       else
1159         {
1160           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1161           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1162         }
1163       NSRectFill (br);
1164     }
1167   /* set up for character rendering */
1168   r.origin.y += font->voffset + (s->height - font->height)/2;
1170   col = (NS_FACE_FOREGROUND (face) != 0
1171          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1172          : FRAME_FOREGROUND_COLOR (s->f));
1173   /* FIXME: find another way to pass this */
1174   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1175            : (NS_FACE_BACKGROUND (face) != 0
1176               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1177               : FRAME_BACKGROUND_COLOR (s->f)));
1179   /* render under GNUstep using DPS */
1180 #ifdef NS_IMPL_GNUSTEP
1181   {
1182     NSGraphicsContext *context = GSCurrentContext ();
1184     DPSgsave (context);
1185     [font->nsfont set];
1187     /* do erase if "foreground" mode */
1188     if (bgCol != nil)
1189       {
1190         [bgCol set];
1191         DPSmoveto (context, r.origin.x, r.origin.y);
1192 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1193         DPSxshow (context, cbuf, advances, len);
1194         DPSstroke (context);
1195         [col set];
1196 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1197       }
1199     /* do underline */
1200     if (face->underline_p)
1201       {
1202         if (face->underline_color != 0)
1203           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1204         else
1205           [col set];
1206         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1207         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1208         if (face->underline_color != 0)
1209           [col set];
1210       }
1211     else
1212       [col set];
1214     /* draw with DPSxshow () */
1215     DPSmoveto (context, r.origin.x, r.origin.y);
1216     DPSxshow (context, cbuf, advances, len);
1217     DPSstroke (context);
1219     DPSgrestore (context);
1220   }
1222 #else  /* NS_IMPL_COCOA */
1223   {
1224     CGContextRef gcontext =
1225       [[NSGraphicsContext currentContext] graphicsPort];
1226     static CGAffineTransform fliptf;
1227     static BOOL firstTime = YES;
1229     if (firstTime)
1230       {
1231         firstTime = NO;
1232         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1233       }
1235     CGContextSaveGState (gcontext);
1237     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1239     CGContextSetFont (gcontext, font->cgfont);
1240     CGContextSetFontSize (gcontext, font->size);
1241     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1242       CGContextSetShouldAntialias (gcontext, 0);
1243     else
1244       CGContextSetShouldAntialias (gcontext, 1);
1246     CGContextSetTextMatrix (gcontext, fliptf);
1248     if (bgCol != nil)
1249       {
1250         /* foreground drawing; erase first to avoid overstrike */
1251         [bgCol set];
1252         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1253         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1254         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1255         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1256       }
1258     if (face->underline_p)
1259       {
1260         if (face->underline_color != 0)
1261           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1262         else
1263           [col set];
1264         CGContextBeginPath (gcontext);
1265         CGContextMoveToPoint (gcontext,
1266                               r.origin.x, r.origin.y + font->underpos);
1267         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1268                                 r.origin.y + font->underpos);
1269         CGContextStrokePath (gcontext);
1270         if (face->underline_color != 0)
1271           [col set];
1272       }
1273     else
1274       [col set];
1276     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1277     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1278                                     advances, len);
1280     if (face->overstrike)
1281       {
1282         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1283         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1284                                         advances, len);
1285       }
1287     CGContextRestoreGState (gcontext);
1288   }
1289 #endif  /* NS_IMPL_COCOA */
1290   return to-from;
1295 /* ==========================================================================
1297     Font glyph and metrics caching functions
1299    ========================================================================== */
1301 /* Find and cache corresponding glyph codes for unicode values in given
1302    hi-byte block of 256. */
1303 static void
1304 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1306 #ifdef NS_IMPL_COCOA
1307   static EmacsGlyphStorage *glyphStorage;
1308   static char firstTime = 1;
1309 #endif
1310   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1311   unsigned int i, g, idx;
1312   unsigned short *glyphs;
1314   if (NSFONT_TRACE)
1315     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1316             font_info, block);
1318  BLOCK_INPUT;
1320 #ifdef NS_IMPL_COCOA
1321   if (firstTime)
1322     {
1323       firstTime = 0;
1324       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1325     }
1326 #endif
1328   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1329   if (!unichars || !(font_info->glyphs[block]))
1330     abort ();
1332   /* create a string containing all unicode characters in this block */
1333   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1334     if (idx < 0xD800 || idx > 0xDFFF)
1335       unichars[i] = idx;
1336     else
1337       unichars[i] = 0xFEFF;
1338   unichars[0x100] = 0;
1340   {
1341 #ifdef NS_IMPL_COCOA
1342     NSString *allChars = [[NSString alloc]
1343                                initWithCharactersNoCopy: unichars
1344                                                  length: 0x100
1345                                            freeWhenDone: NO];
1346     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1347     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1348     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1349     NSUInteger gInd =0, cInd =0;
1351     [glyphStorage setString: allChars font: font_info->nsfont];
1352     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1353                         desiredNumberOfCharacters: glyphStorage->maxChar
1354                                        glyphIndex: &gInd characterIndex: &cInd];
1355 #endif
1356     glyphs = font_info->glyphs[block];
1357     for (i =0; i<0x100; i++, glyphs++)
1358       {
1359 #ifdef NS_IMPL_GNUSTEP
1360         g = unichars[i];
1361 #else
1362         g = glyphStorage->cglyphs[i];
1363         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1364         if (g > numGlyphs)
1365           g = 0xFFFF; /* hopefully unused... */
1366 #endif
1367         *glyphs = g;
1368       }
1370 #ifdef NS_IMPL_COCOA
1371     [allChars release];
1372 #endif
1373   }
1375   UNBLOCK_INPUT;
1376   xfree (unichars);
1380 /* Determine and cache metrics for corresponding glyph codes in given
1381    hi-byte block of 256. */
1382 static void
1383 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1385   unsigned int i, g;
1386   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1387   NSFont *sfont;
1388   struct font_metrics *metrics;
1390   if (NSFONT_TRACE)
1391     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1392             font_info, block);
1394 #ifdef NS_IMPL_GNUSTEP
1395   /* not implemented yet (as of startup 0.18), so punt */
1396   if (numGlyphs == 0)
1397     numGlyphs = 0x10000;
1398 #endif
1400  BLOCK_INPUT;
1401  sfont = [font_info->nsfont screenFont];
1403   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1404   memset (font_info->metrics[block], 0, 0x100 * sizeof (struct font_metrics));
1405   if (!(font_info->metrics[block]))
1406     abort ();
1408   metrics = font_info->metrics[block];
1409   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1410     {
1411       float w, lb, rb;
1412       NSRect r = [sfont boundingRectForGlyph: g];
1414       w = max ([sfont advancementForGlyph: g].width, 2.0);
1415       metrics->width = lrint (w);
1417       lb = r.origin.x;
1418       rb = r.size.width - w;
1419       if (lb < 0)
1420         metrics->lbearing = round (lb);
1421       if (font_info->ital)
1422         rb += 0.22 * font_info->height;
1423       metrics->rbearing = lrint (w + rb);
1425       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1426  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1427       metrics->ascent = r.size.height - metrics->descent;
1428 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1429     }
1430   UNBLOCK_INPUT;
1434 #ifdef NS_IMPL_COCOA
1435 /* helper for font glyph setup */
1436 @implementation EmacsGlyphStorage
1438 - init
1440   return [self initWithCapacity: 1024];
1443 - initWithCapacity: (unsigned long) c
1445   self = [super init];
1446   maxChar = 0;
1447   maxGlyph = 0;
1448   dict = [NSMutableDictionary new];
1449   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1450   return self;
1453 - (void) dealloc
1455   if (attrStr != nil)
1456     [attrStr release];
1457   [dict release];
1458   xfree (cglyphs);
1459   [super dealloc];
1462 - (void) setString: (NSString *)str font: (NSFont *)font
1464   [dict setObject: font forKey: NSFontAttributeName];
1465   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1466   maxChar = [str length];
1467   maxGlyph = 0;
1470 /* NSGlyphStorage protocol */
1471 - (NSUInteger)layoutOptions
1473   return 0;
1476 - (NSAttributedString *)attributedString
1478   return attrStr;
1481 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1482         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1483         characterIndex: (NSUInteger)charIndex
1485   len = glyphIndex+length;
1486   for (i =glyphIndex; i<len; i++)
1487     cglyphs[i] = glyphs[i-glyphIndex];
1488   if (len > maxGlyph)
1489     maxGlyph = len;
1492 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1493         forGlyphAtIndex: (NSUInteger)glyphIndex
1495   return;
1498 @end
1499 #endif /* NS_IMPL_COCOA */
1502 /* Debugging */
1503 void
1504 ns_dump_glyphstring (struct glyph_string *s)
1506   int i;
1508   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1509 "overlap = %d, bg_filled = %d:",
1510            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1511            s->row->overlapping_p, s->background_filled_p);
1512   for (i =0; i<s->nchars; i++)
1513     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1514   fprintf (stderr, "\n");
1518 void
1519 syms_of_nsfont (void)
1521   nsfont_driver.type = Qns;
1522   register_font_driver (&nsfont_driver, NULL);
1523   DEFSYM (Qapple, "apple");
1524   DEFSYM (Qroman, "roman");
1525   DEFSYM (Qmedium, "medium");
1526   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1527                doc: /* Internal use: maps font registry to unicode script. */);