* lisp/gnus/smime.el (smime-mode): Use define-derived-mode.
[emacs.git] / src / nsfont.m
blobb38987588694c4847b36be00fb151faaab45a536
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 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 Vns_reg_to_script;
52 static Lisp_Object Qapple, Qroman, Qmedium;
53 extern Lisp_Object Qappend;
54 extern Lisp_Object ns_antialias_text;
55 extern float ns_antialias_threshold;
56 extern int ns_tmp_flags;
57 extern struct nsfont_info *ns_tmp_font;
59 /* font glyph and metrics caching functions, implemented at end */
60 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
61                               unsigned char block);
62 static void ns_glyph_metrics (struct nsfont_info *font_info,
63                               unsigned char block);
66 /* ==========================================================================
68     Utilities
70    ========================================================================== */
73 /* Replace spaces w/another character so emacs core font parsing routines
74    aren't thrown off. */
75 static void
76 ns_escape_name (char *name)
78   int i =0, len =strlen (name);
79   for ( ; i<len; i++)
80     if (name[i] == ' ')
81       name[i] = '_';
85 /* Reconstruct spaces in a font family name passed through emacs. */
86 static void
87 ns_unescape_name (char *name)
89   int i =0, len =strlen (name);
90   for ( ; i<len; i++)
91     if (name[i] == '_')
92       name[i] = ' ';
96 /* Extract family name from a font spec. */
97 static NSString *
98 ns_get_family (Lisp_Object font_spec)
100   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
101   if (NILP (tem))
102       return nil;
103   else
104     {
105       char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
106       NSString *family;
107       ns_unescape_name (tmp);
108       family = [NSString stringWithUTF8String: tmp];
109       free (tmp);
110       return family;
111     }
115 /* Return 0 if attr not set, else value (which might also be 0).
116    On Leopard 0 gets returned even on descriptors where the attribute
117    was never set, so there's no way to distinguish between unspecified
118    and set to not have.  Callers should assume 0 means unspecified. */
119 static float
120 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
122     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
123     NSNumber *val = [tdict objectForKey: trait];
124     return val == nil ? 0.0 : [val floatValue];
128 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
129    to NSFont descriptor.  Information under extra only needed for matching. */
130 #define STYLE_REF 100
131 static NSFontDescriptor
132 *ns_spec_to_descriptor(Lisp_Object font_spec)
134     NSFontDescriptor *fdesc;
135     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
136     NSMutableDictionary *tdict = [NSMutableDictionary new];
137     NSString *family = ns_get_family (font_spec);
138     float n;
140     /* add each attr in font_spec to fdAttrs.. */
141     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
142     if (n != -1 && n != STYLE_REF)
143         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
144                   forKey: NSFontWeightTrait];
145     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
146     if (n != -1 && n != STYLE_REF)
147         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
148                   forKey: NSFontSlantTrait];
149     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
150     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
151         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
152                   forKey: NSFontWidthTrait];
153     if ([tdict count] > 0)
154         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
156     fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
157     if (family != nil)
158         fdesc = [fdesc fontDescriptorWithFamily: family];
159     return fdesc;
163 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
164 static Lisp_Object
165 ns_descriptor_to_entity (NSFontDescriptor *desc,
166                          Lisp_Object extra,
167                          const char *style)
169     Lisp_Object font_entity = font_make_entity ();
170     /*   NSString *psName = [desc postscriptName]; */
171     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
172     unsigned int traits = [desc symbolicTraits];
173     char *escapedFamily;
175     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
176     if (family == nil)
177       family = [desc objectForKey: NSFontNameAttribute];
178     if (family == nil)
179       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
181     escapedFamily = strdup ([family UTF8String]);
182     ns_escape_name (escapedFamily);
184     ASET (font_entity, FONT_TYPE_INDEX, Qns);
185     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
186     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
187     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
188     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
190     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
191                     traits & NSFontBoldTrait ? Qbold : Qmedium);
192 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
193                     make_number (100 + 100
194                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
195     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
196                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
197 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
198                     make_number (100 + 100
199                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
200     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
201                     traits & NSFontCondensedTrait ? Qcondensed :
202                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
203 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
204                     make_number (100 + 100
205                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
207     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
208     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
209     ASET (font_entity, FONT_SPACING_INDEX,
210           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
211               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
213     ASET (font_entity, FONT_EXTRA_INDEX, extra);
214     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
216     if (NSFONT_TRACE)
217       {
218         fprintf (stderr, "created font_entity:\n    ");
219         debug_print (font_entity);
220       }
222     free (escapedFamily);
223     return font_entity;
227 /* Default font entity. */
228 static Lisp_Object
229 ns_fallback_entity (void)
231   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
232       fontDescriptor], Qnil, NULL);
236 /* Utility: get width of a char c in screen font sfont */
237 static float
238 ns_char_width (NSFont *sfont, int c)
240     float w;
241     NSString *cstr = [NSString stringWithFormat: @"%c", c];
242 #ifdef NS_IMPL_COCOA
243     NSGlyph glyph = [sfont glyphWithName: cstr];
244     if (glyph)
245       {
246         float w = [sfont advancementForGlyph: glyph].width;
247         if (w >= 1.5)
248             return w;
249       }
250 #endif
251     {
252       NSDictionary *attrsDictionary =
253         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
254       w = [cstr sizeWithAttributes: attrsDictionary].width;
255     }
256     return max (w, 2.0);
260 /* Return whether set1 covers set2 to a reasonable extent given by pct.
261    We check, out of each 16 unicode char range containing chars in set2,
262    whether at least one character is present in set1.
263    This must be true for pct of the pairs to consider it covering. */
264 static BOOL
265 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
267     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
268     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
269     int i, off = 0, tot = 0;
271     for (i=0; i<4096; i++, bytes1++, bytes2++)
272         if (*bytes2)
273           {
274             tot++;
275             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
276                 off++;
277           }
278 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
279     return (float)off / tot < 1.0 - pct;
283 /* Convert :lang property to a script.  Use of :lang property by font backend
284    seems to be limited for now (2009/05) to ja, zh, and ko. */
285 static NSString
286 *ns_lang_to_script (Lisp_Object lang)
288     if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
289         return @"han";
290     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
291              have more characters. */
292     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
293         return @"han";
294     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
295         return @"hangul";
296     else
297         return @"";
301 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
302    everyone just use some standard unicode names for these?) */
303 static NSString
304 *ns_otf_to_script (Lisp_Object otf)
306     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
307     return CONSP (script)
308         ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
309         : @"";
313 /* Convert a font registry, such as  */
314 static NSString
315 *ns_registry_to_script (char *reg)
317     Lisp_Object script, r, rts = Vns_reg_to_script;
318     while CONSP (rts)
319       {
320         r = XCAR (XCAR (rts));
321         if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
322           {
323             script = XCDR (XCAR (rts));
324             return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
325           }
326         rts = XCDR (rts);
327       }
328     return  @"";
332 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
333    plus registry regular property, for something that can be mapped to a
334    unicode script.  Empty string returned if no script spec found. */
335 static NSString
336 *ns_get_req_script (Lisp_Object font_spec)
338     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
339     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
341     /* The extra-bundle properties have priority. */
342     for ( ; CONSP (extra); extra = XCDR (extra))
343       {
344         Lisp_Object tmp = XCAR (extra);
345         if (CONSP (tmp))
346           {
347             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
348             if (EQ (key, QCscript) && SYMBOLP (val))
349                 return [NSString stringWithUTF8String:
350                             SDATA (SYMBOL_NAME (val))];
351             if (EQ (key, QClang) && SYMBOLP (val))
352                 return ns_lang_to_script (val);
353             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
354                 return ns_otf_to_script (val);
355           }
356       }
358     /* If we get here, check the charset portion of the registry. */
359     if (! NILP (reg))
360       {
361         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
362            (which causes box rendering if we don't treat it like iso8858-1)
363            but also for ascii (which causes unnecessary font substitution). */
364 #if 0
365         if (EQ (reg, Qiso10646_1))
366           reg = Qiso8859_1;
367 #endif
368         return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
369       }
371     return @"";
375 /* This small function is static in fontset.c.  If it can be made public for
376    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
377 static void
378 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
380     if (EQ (XCAR (arg), val))
381       {
382         if (CONSP (range))
383           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
384         else
385           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
386       }
390 /* Use the unicode range information in Vchar_script_table to convert a script
391    name into an NSCharacterSet. */
392 static NSCharacterSet
393 *ns_script_to_charset (NSString *scriptName)
395     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
396     Lisp_Object script = intern ([scriptName UTF8String]);
397     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
399     if (! NILP (Fmemq (script, script_list)))
400       {
401         Lisp_Object ranges, range_list;
403         ranges = Fcons (script, Qnil);
404         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
405                         ranges);
406         range_list = Fnreverse (XCDR (ranges));
407         if (! NILP (range_list))
408           {
409             for (; CONSP (range_list); range_list = XCDR (range_list))
410               {
411                 int start = XINT (XCAR (XCAR (range_list)));
412                 int end = XINT (XCDR (XCAR (range_list)));
413                 if (NSFONT_TRACE)
414                     debug_print (XCAR (range_list));
415                 if (end < 0x10000)
416                     [charset addCharactersInRange:
417                         NSMakeRange (start, end-start)];
418               }
419           }
420       }
421     return charset;
425 /* Return an array of font families containing characters for the given
426    script, for the given coverage criterion, including at least LastResort.
427    Results are cached by script for faster access.
428    If none are found, we reduce the percentage and try again, until 5%.
429    This provides a font with at least some characters if such can be found.
430    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
431    (b) need approximate match as fonts covering full unicode ranges are rare. */
432 static NSSet
433 *ns_get_covering_families (NSString *script, float pct)
435     static NSMutableDictionary *scriptToFamilies = nil;
436     NSMutableSet *families;
438     if (NSFONT_TRACE)
439         NSLog(@"Request covering families for script: '%@'", script);
441     if (scriptToFamilies == nil)
442         scriptToFamilies = [[NSMutableDictionary alloc] init];
444     if ((families = [scriptToFamilies objectForKey: script]) == nil)
445       {
446         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
447         NSArray *allFamilies = [fontMgr availableFontFamilies];
449         if ([script length] == 0)
450             families = [NSMutableSet setWithArray: allFamilies];
451         else
452           {
453             NSCharacterSet *charset = ns_script_to_charset (script);
454             NSString *family;
455             families = [NSMutableSet setWithCapacity: 10];
456             while (1)
457               {
458                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
459                 while (family = [allFamiliesEnum nextObject])
460                   {
461                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
462                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
463                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
464                     if (fset == nil)
465                       fset = [NSCharacterSet characterSetWithRange:
466                                                NSMakeRange (0, 127)];
467                     if (ns_charset_covers(fset, charset, pct))
468                         [families addObject: family];
469                   }
470                 pct -= 0.2;
471                 if ([families count] > 0 || pct < 0.05)
472                     break;
473               }
474           }
475 #ifdef NS_IMPL_COCOA
476         if ([families count] == 0)
477             [families addObject: @"LastResort"];
478 #endif
479         [scriptToFamilies setObject: families forKey: script];
480       }
482     if (NSFONT_TRACE)
483         NSLog(@"    returning %d families", [families count]);
484     return families;
488 /* Implementation for list() and match().  List() can return nil, match()
489 must return something.  Strategy is to drop family name from attribute
490 matching set for match. */
491 static Lisp_Object
492 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
494     Lisp_Object tem, list = Qnil;
495     NSFontDescriptor *fdesc, *desc;
496     NSMutableSet *fkeys;
497     NSArray *matchingDescs;
498     NSEnumerator *dEnum;
499     NSString *family;
500     NSSet *cFamilies;
501     BOOL foundItal = NO;
503     if (NSFONT_TRACE)
504       {
505         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
506                  (isMatch ? "match" : "list"));
507         debug_print (font_spec);
508       }
510     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
512     fdesc = ns_spec_to_descriptor (font_spec);
513     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
514     if (isMatch)
515         [fkeys removeObject: NSFontFamilyAttribute];
517     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
518     if (NSFONT_TRACE)
519         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
520               [matchingDescs count]);
522     for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
523       {
524         if (![cFamilies containsObject:
525                  [desc objectForKey: NSFontFamilyAttribute]])
526             continue;
527         tem = ns_descriptor_to_entity (desc,
528                                          AREF (font_spec, FONT_EXTRA_INDEX),
529                                        NULL);
530         if (isMatch)
531           return tem;
532         list = Fcons (tem, list);
533         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
534             foundItal = YES;
535       }
537     /* Add synthItal member if needed. */
538     family = [fdesc objectForKey: NSFontFamilyAttribute];
539     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
540       {
541         NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
542             fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
543             fontDescriptorWithFamily: family];
544         list = Fcons (ns_descriptor_to_entity (sDesc,
545                                          AREF (font_spec, FONT_EXTRA_INDEX),
546                                          "synthItal"), list);
547       }
549     /* Return something if was a match and nothing found. */
550     if (isMatch)
551       return ns_fallback_entity ();
553     if (NSFONT_TRACE)
554         fprintf (stderr, "    Returning %ld entities.\n",
555                  (long) XINT (Flength (list)));
557     return list;
562 /* ==========================================================================
564     Font driver implementation
566    ========================================================================== */
569 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
570 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
571 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
572 static Lisp_Object nsfont_list_family (Lisp_Object frame);
573 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
574                                  int pixel_size);
575 static void nsfont_close (FRAME_PTR f, struct font *font);
576 static int nsfont_has_char (Lisp_Object entity, int c);
577 static unsigned int nsfont_encode_char (struct font *font, int c);
578 static int nsfont_text_extents (struct font *font, unsigned int *code,
579                                 int nglyphs, struct font_metrics *metrics);
580 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
581                         int with_background);
583 struct font_driver nsfont_driver =
584   {
585     0,                          /* Qns */
586     1,                          /* case sensitive */
587     nsfont_get_cache,
588     nsfont_list,
589     nsfont_match,
590     nsfont_list_family,
591     NULL,                       /*free_entity */
592     nsfont_open,
593     nsfont_close,
594     NULL,                       /* prepare_face */
595     NULL,                       /* done_face */
596     nsfont_has_char,
597     nsfont_encode_char,
598     nsfont_text_extents,
599     nsfont_draw,
600     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
601                  anchor_point, otf_capability, otf_driver,
602                  start_for_frame, end_for_frame, shape */
603   };
606 /* Return a cache of font-entities on FRAME.  The cache must be a
607    cons whose cdr part is the actual cache area.  */
608 static Lisp_Object
609 nsfont_get_cache (FRAME_PTR frame)
611   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
612   return (dpyinfo->name_list_element);
616 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
617    **list** of font-entities.  This and match () are sole APIs that allocate
618    font-entities.  Properties to be considered (2009/05/19) are:
619    regular: foundry, family, adstyle, registry
620    extended: script, lang, otf
621   "Extended" properties are not part of the vector but get stored as
622    lisp properties under FONT_EXTRA_INDEX.
624    The returned entities should have type set (to 'ns), plus the following:
625    foundry, family, adstyle, registry,
626    weight, slant, width, size (0 if scalable),
627    dpi, spacing, avgwidth (0 if scalable)  */
628 static Lisp_Object
629 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
631     return ns_findfonts (font_spec, NO);
635 /* Return a font entity most closely maching with FONT_SPEC on
636    FRAME.  The closeness is determined by the font backend, thus
637    `face-font-selection-order' is ignored here.
638    Properties to be considered are same as for list(). */
639 static Lisp_Object
640 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
642     return ns_findfonts(font_spec, YES);
646 /* List available families.  The value is a list of family names
647    (symbols). */
648 static Lisp_Object
649 nsfont_list_family (Lisp_Object frame)
651   Lisp_Object list = Qnil;
652   NSEnumerator *families =
653     [[[NSFontManager sharedFontManager] availableFontFamilies]
654       objectEnumerator];
655   NSString *family;
656   while (family = [families nextObject])
657       list = Fcons (intern ([family UTF8String]), list);
658   /* FIXME: escape the name? */
660   if (NSFONT_TRACE)
661     fprintf (stderr, "nsfont: list families returning %ld entries\n",
662             (long) XINT (Flength (list)));
664   return list;
668 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
669    scalable, open it with PIXEL_SIZE.  */
670 static Lisp_Object
671 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
673   BOOL synthItal;
674   unsigned int traits = 0;
675   struct nsfont_info *font_info;
676   struct font *font;
677   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
678   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
679   NSString *family;
680   NSFont *nsfont, *sfont;
681   Lisp_Object tem;
682   NSRect brect;
683   Lisp_Object font_object;
684   int i;
685   int fixLeopardBug;
686   static NSMutableDictionary *fontCache = nil;
687   NSNumber *cached;
689   /* 2008/03/08: The same font may end up being requested for different
690      entities, due to small differences in numeric values or other issues,
691      or for different copies of the same entity.  Therefore we cache to
692      avoid creating multiple struct font objects (with metrics cache, etc.)
693      for the same NSFont object. */
694   if (fontCache == nil)
695     fontCache = [[NSMutableDictionary alloc] init];
697   if (NSFONT_TRACE)
698     {
699       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
700       debug_print (font_entity);
701     }
703   if (pixel_size <= 0)
704     {
705       /* try to get it out of frame params */
706         Lisp_Object tem = get_frame_param (f, Qfontsize);
707         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
708     }
710   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
711   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
712                                        9);
713   family = ns_get_family (font_entity);
714   if (family == nil)
715     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
716   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
717      when setting family in ns_spec_to_descriptor(). */
718   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
719       traits |= NSBoldFontMask;
720   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
721       traits |= NSItalicFontMask;
723   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
724   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
725   nsfont = [fontMgr fontWithFamily: family
726                             traits: traits weight: fixLeopardBug
727                               size: pixel_size];
728   /* if didn't find, try synthetic italic */
729   if (nsfont == nil && synthItal)
730     {
731       nsfont = [fontMgr fontWithFamily: family
732                                 traits: traits & ~NSItalicFontMask
733                                 weight: fixLeopardBug size: pixel_size];
734     }
735 #ifdef NS_IMPL_COCOA
736   /* LastResort not really a family */
737   if (nsfont == nil && [@"LastResort" isEqualToString: family])
738       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
739 #endif
741   if (nsfont == nil)
742     {
743       message_with_string ("*** Warning: font in family '%s' not found",
744                           build_string ([family UTF8String]), 1);
745       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
746     }
748   if (NSFONT_TRACE)
749     NSLog (@"%@\n", nsfont);
751   /* Check the cache */
752   cached = [fontCache objectForKey: nsfont];
753   if (cached != nil && !synthItal)
754     {
755       if (NSFONT_TRACE)
756         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
757       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
758       XHASH (font_object) = [cached unsignedLongValue];
759       return font_object;
760     }
761   else
762     {
763       font_object = font_make_object (VECSIZE (struct nsfont_info),
764                                       font_entity, pixel_size);
765       if (!synthItal)
766         [fontCache setObject: [NSNumber numberWithUnsignedLong:
767                                           (unsigned long) XHASH (font_object)]
768                       forKey: nsfont];
769     }
771   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
772   font = (struct font *) font_info;
773   if (!font)
774     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
776   font_info->glyphs = (unsigned short **)
777     xmalloc (0x100 * sizeof (unsigned short *));
778   font_info->metrics = (struct font_metrics **)
779     xmalloc (0x100 * sizeof (struct font_metrics *));
780   if (!font_info->glyphs || !font_info->metrics)
781     return Qnil;
782   memset (font_info->glyphs, 0, 0x100 * sizeof (unsigned short *));
783   memset (font_info->metrics, 0, 0x100 * sizeof (struct font_metrics *));
785   BLOCK_INPUT;
787   /* for metrics */
788   sfont = [nsfont screenFont];
789   if (sfont == nil)
790     sfont = nsfont;
792   /* non-metric backend font struct fields */
793   font = (struct font *) font_info;
794   font->pixel_size = [sfont pointSize];
795   font->driver = &nsfont_driver;
796   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
797   font->encoding_charset = -1;
798   font->repertory_charset = -1;
799   font->default_ascent = 0;
800   font->vertical_centering = 0;
801   font->baseline_offset = 0;
802   font->relative_compose = 0;
803   font->font_encoder = NULL;
805   font->props[FONT_FORMAT_INDEX] = Qns;
806   font->props[FONT_FILE_INDEX] = Qnil;
808   {
809     double expand, hshrink;
810     float full_height, min_height, hd;
811     const char *fontName = [[nsfont fontName] UTF8String];
812     int len = strlen (fontName);
814 #ifdef NS_IMPL_GNUSTEP
815     font_info->nsfont = sfont;
816 #else
817     font_info->nsfont = nsfont;
818 #endif
819     [font_info->nsfont retain];
821     /* set up ns_font (defined in nsgui.h) */
822     font_info->name = (char *)xmalloc (strlen (fontName)+1);
823     strcpy (font_info->name, fontName);
824     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
825     font_info->ital =
826       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
828     /* Metrics etc.; some fonts return an unusually large max advance, so we
829        only use it for fonts that have wide characters. */
830     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
831       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
833     brect =  [sfont boundingRectForFont];
834     full_height = brect.size.height;
835     min_height = [sfont ascender] - [sfont descender];
836     hd = full_height - min_height;
838     /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
839     expand = 0.0;
840     hshrink = 1.0;
842     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
843     font_info->underwidth = [sfont underlineThickness];
844     font_info->size = font->pixel_size;
845     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
847     /* max bounds */
848     font_info->max_bounds.ascent =
849       lrint (hshrink * [sfont ascender] + expand * hd/2);
850     /* [sfont descender] is usually negative.  Use floor to avoid
851        clipping descenders. */
852     font_info->max_bounds.descent =
853       -lrint (floor(hshrink* [sfont descender] - expand*hd/2));
854     font_info->height =
855       font_info->max_bounds.ascent + font_info->max_bounds.descent;
856     font_info->max_bounds.width = lrint (font_info->width);
857     font_info->max_bounds.lbearing = lrint (brect.origin.x);
858     font_info->max_bounds.rbearing =
859       lrint (brect.size.width - font_info->width);
861 #ifdef NS_IMPL_COCOA
862     /* set up synthItal and the CG font */
863     font_info->synthItal = synthItal;
864     {
865       ATSFontRef atsFont = ATSFontFindFromPostScriptName
866         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
868       if (atsFont == kATSFontRefUnspecified)
869         {
870           /* see if we can get it by dropping italic (then synthesizing) */
871           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
872               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
873                 fontName], kATSOptionFlagsDefault);
874           if (atsFont != kATSFontRefUnspecified)
875               font_info->synthItal = YES;
876           else
877             {
878               /* last resort fallback */
879               atsFont = ATSFontFindFromPostScriptName
880                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
881             }
882         }
883       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
884     }
885 #endif
887     /* set up metrics portion of font struct */
888     font->ascent = lrint([sfont ascender]);
889     font->descent = -lrint(floor([sfont descender]));
890     font->min_width = ns_char_width(sfont, '|');
891     font->space_width = lrint (ns_char_width (sfont, ' '));
892     font->average_width = lrint (font_info->width);
893     font->max_width = lrint (font_info->max_bounds.width);
894     font->height = lrint (font_info->height);
895     font->underline_position = lrint (font_info->underpos);
896     font->underline_thickness = lrint (font_info->underwidth);
898     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
899     font->props[FONT_FULLNAME_INDEX] =
900       make_unibyte_string (font_info->name, strlen (font_info->name));
901   }
902   UNBLOCK_INPUT;
904   return font_object;
908 /* Close FONT on frame F. */
909 static void
910 nsfont_close (FRAME_PTR f, struct font *font)
912   struct nsfont_info *font_info = (struct nsfont_info *)font;
913   int i;
915   /* FIXME: this occurs apparently due to same failure to detect same font
916             that causes need for cache in nsfont_open () */
917   if (!font_info)
918       return;
920   for (i =0; i<0x100; i++)
921     {
922       xfree (font_info->glyphs[i]);
923       xfree (font_info->metrics[i]);
924     }
925   [font_info->nsfont release];
926 #ifdef NS_IMPL_COCOA
927   CGFontRelease (font_info->cgfont);
928 #endif
929   xfree (font_info->name);
930   xfree (font_info);
934 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
935    return 1.  If not, return 0.  If a font must be opened to check
936    it, return -1. */
937 static int
938 nsfont_has_char (Lisp_Object entity, int c)
940   return -1;
944 /* Return a glyph code of FONT for character C (Unicode code point).
945    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
946 static unsigned int
947 nsfont_encode_char (struct font *font, int c)
949   struct nsfont_info *font_info = (struct nsfont_info *)font;
950   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
951   unsigned short g;
953   if (c > 0xFFFF)
954     return FONT_INVALID_CODE;
956   /* did we already cache this block? */
957   if (!font_info->glyphs[high])
958     ns_uni_to_glyphs (font_info, high);
960   g = font_info->glyphs[high][low];
961   return g == 0xFFFF ? FONT_INVALID_CODE : g;
965 /* Perform the size computation of glyphs of FONT and fill in members
966    of METRICS.  The glyphs are specified by their glyph codes in
967    CODE (length NGLYPHS). */
968 static int
969 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
970                      struct font_metrics *metrics)
972   struct nsfont_info *font_info = (struct nsfont_info *)font;
973   struct font_metrics *pcm;
974   unsigned char high, low;
975   int totalWidth = 0;
976   int i;
978   memset (metrics, 0, sizeof (struct font_metrics));
980   for (i =0; i<nglyphs; i++)
981     {
982       /* get metrics for this glyph, filling cache if need be */
983       /* TODO: get metrics for whole string from an NSLayoutManager
984                (if not too slow) */
985       high = (code[i] & 0xFF00) >> 8;
986       low = code[i] & 0x00FF;
987       if (!font_info->metrics[high])
988         ns_glyph_metrics (font_info, high);
989       pcm = &(font_info->metrics[high][low]);
991       if (metrics->lbearing > totalWidth + pcm->lbearing)
992         metrics->lbearing = totalWidth + pcm->lbearing;
993       if (metrics->rbearing < totalWidth + pcm->rbearing)
994         metrics->rbearing = totalWidth + pcm->rbearing;
995       if (metrics->ascent < pcm->ascent)
996         metrics->ascent = pcm->ascent;
997       if (metrics->descent < pcm->descent)
998         metrics->descent = pcm->descent;
1000       totalWidth += pcm->width;
1001     }
1003   metrics->width = totalWidth;
1005   return totalWidth; /* not specified in doc, but xfont.c does it */
1009 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1010    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
1011    is nonzero, fill the background in advance.  It is assured that
1012    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1013 static int
1014 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1015              int with_background)
1016 /* NOTE: focus and clip must be set
1017      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1019   static char cbuf[1024];
1020   char *c = cbuf;
1021 #ifdef NS_IMPL_GNUSTEP
1022   static float advances[1024];
1023   float *adv = advances;
1024 #else
1025   static CGSize advances[1024];
1026   CGSize *adv = advances;
1027 #endif
1028   struct face *face;
1029   NSRect r;
1030   struct nsfont_info *font = ns_tmp_font;
1031   NSColor *col, *bgCol;
1032   unsigned short *t = s->char2b;
1033   int i, len;
1034   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1035   int end = isComposite ? s->cmp_to : s->nchars;
1037   /* Select face based on input flags */
1038   switch (ns_tmp_flags)
1039     {
1040     case NS_DUMPGLYPH_CURSOR:
1041       face = s->face;
1042       break;
1043     case NS_DUMPGLYPH_MOUSEFACE:
1044       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1045       if (!face)
1046         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1047       break;
1048     default:
1049       face = s->face;
1050     }
1052   r.origin.x = s->x;
1053   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1054     r.origin.x += abs (s->face->box_line_width);
1056   r.origin.y = s->y;
1057   r.size.height = FONT_HEIGHT (font);
1059   /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
1060      NS to render the string, it will come out differently from the individual
1061      character widths added up because of layout processing. */
1062   {
1063     XCharStruct *cs;
1064     int cwidth, twidth = 0;
1065     int hi, lo;
1066     /* FIXME: composition: no vertical displacement is considered. */
1067     t += s->cmp_from; /* advance into composition */
1068     for (i = s->cmp_from; i < end; i++, t++)
1069       {
1070         hi = (*t & 0xFF00) >> 8;
1071         lo = *t & 0x00FF;
1072         if (isComposite)
1073           {
1074             if (!s->first_glyph->u.cmp.automatic)
1075                 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1076             else
1077               {
1078                 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1079                 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1080                 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1081                     cwidth = LGLYPH_WIDTH (glyph);
1082                 else
1083                   {
1084                     cwidth = LGLYPH_WADJUST (glyph);
1085 #ifdef NS_IMPL_GNUSTEP
1086                     *(adv-1) += LGLYPH_XOFF (glyph);
1087 #else
1088                     (*(adv-1)).width += LGLYPH_XOFF (glyph);
1089 #endif
1090                   }
1091               }
1092           }
1093         else
1094           {
1095             if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1096               ns_glyph_metrics (font, hi);
1097             cwidth = font->metrics[hi][lo].width;
1098           }
1099         twidth += cwidth;
1100 #ifdef NS_IMPL_GNUSTEP
1101         *adv++ = cwidth;
1102         CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1103 #else
1104         (*adv++).width = cwidth;
1105 #endif
1106       }
1107     len = adv - advances;
1108     r.size.width = twidth;
1109     *c = 0;
1110   }
1112   /* fill background if requested */
1113   if (with_background && !isComposite)
1114     {
1115       NSRect br = r;
1116       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1117       int mbox_line_width = max (s->face->box_line_width, 0);
1119       if (s->row->full_width_p)
1120         {
1121           if (br.origin.x <= fibw + 1 + mbox_line_width)
1122             {
1123               br.size.width += br.origin.x - mbox_line_width;
1124               br.origin.x = mbox_line_width;
1125             }
1126           if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1127                 <= fibw+1)
1128             br.size.width += fibw;
1129         }
1130       if (s->face->box == FACE_NO_BOX)
1131         {
1132           /* expand unboxed top row over internal border */
1133           if (br.origin.y <= fibw + 1 + mbox_line_width)
1134             {
1135               br.size.height += br.origin.y;
1136               br.origin.y = 0;
1137             }
1138         }
1139       else
1140         {
1141           int correction = abs (s->face->box_line_width)+1;
1142           br.origin.y += correction;
1143           br.size.height -= 2*correction;
1144           br.origin.x += correction;
1145           br.size.width -= 2*correction;
1146         }
1148       if (!s->face->stipple)
1149         [(NS_FACE_BACKGROUND (face) != 0
1150           ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1151           : FRAME_BACKGROUND_COLOR (s->f)) set];
1152       else
1153         {
1154           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1155           [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1156         }
1157       NSRectFill (br);
1158     }
1161   /* set up for character rendering */
1162   r.origin.y += font->voffset + (s->height - font->height)/2;
1164   col = (NS_FACE_FOREGROUND (face) != 0
1165          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1166          : FRAME_FOREGROUND_COLOR (s->f));
1167   /* FIXME: find another way to pass this */
1168   bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1169            : (NS_FACE_BACKGROUND (face) != 0
1170               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1171               : FRAME_BACKGROUND_COLOR (s->f)));
1173   /* render under GNUstep using DPS */
1174 #ifdef NS_IMPL_GNUSTEP
1175   {
1176     NSGraphicsContext *context = GSCurrentContext ();
1178     DPSgsave (context);
1179     [font->nsfont set];
1181     /* do erase if "foreground" mode */
1182     if (bgCol != nil)
1183       {
1184         [bgCol set];
1185         DPSmoveto (context, r.origin.x, r.origin.y);
1186 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1187         DPSxshow (context, cbuf, advances, len);
1188         DPSstroke (context);
1189         [col set];
1190 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1191       }
1193     /* do underline */
1194     if (face->underline_p)
1195       {
1196         if (face->underline_color != 0)
1197           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1198         else
1199           [col set];
1200         DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1201         DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1202         if (face->underline_color != 0)
1203           [col set];
1204       }
1205     else
1206       [col set];
1208     /* draw with DPSxshow () */
1209     DPSmoveto (context, r.origin.x, r.origin.y);
1210     DPSxshow (context, cbuf, advances, len);
1211     DPSstroke (context);
1213     DPSgrestore (context);
1214   }
1216 #else  /* NS_IMPL_COCOA */
1217   {
1218     CGContextRef gcontext =
1219       [[NSGraphicsContext currentContext] graphicsPort];
1220     static CGAffineTransform fliptf;
1221     static BOOL firstTime = YES;
1223     if (firstTime)
1224       {
1225         firstTime = NO;
1226         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1227       }
1229     CGContextSaveGState (gcontext);
1231     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1233     CGContextSetFont (gcontext, font->cgfont);
1234     CGContextSetFontSize (gcontext, font->size);
1235     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1236       CGContextSetShouldAntialias (gcontext, 0);
1237     else
1238       CGContextSetShouldAntialias (gcontext, 1);
1240     CGContextSetTextMatrix (gcontext, fliptf);
1242     if (bgCol != nil)
1243       {
1244         /* foreground drawing; erase first to avoid overstrike */
1245         [bgCol set];
1246         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1247         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1248         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1249         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1250       }
1252     if (face->underline_p)
1253       {
1254         if (face->underline_color != 0)
1255           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1256         else
1257           [col set];
1258         CGContextBeginPath (gcontext);
1259         CGContextMoveToPoint (gcontext,
1260                               r.origin.x, r.origin.y + font->underpos);
1261         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1262                                 r.origin.y + font->underpos);
1263         CGContextStrokePath (gcontext);
1264         if (face->underline_color != 0)
1265           [col set];
1266       }
1267     else
1268       [col set];
1270     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1271     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1272                                     advances, len);
1274     if (face->overstrike)
1275       {
1276         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1277         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1278                                         advances, len);
1279       }
1281     CGContextRestoreGState (gcontext);
1282   }
1283 #endif  /* NS_IMPL_COCOA */
1284   return to-from;
1289 /* ==========================================================================
1291     Font glyph and metrics caching functions
1293    ========================================================================== */
1295 /* Find and cache corresponding glyph codes for unicode values in given
1296    hi-byte block of 256. */
1297 static void
1298 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1300 #ifdef NS_IMPL_COCOA
1301   static EmacsGlyphStorage *glyphStorage;
1302   static char firstTime = 1;
1303 #endif
1304   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1305   unsigned int i, g, idx;
1306   unsigned short *glyphs;
1308   if (NSFONT_TRACE)
1309     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1310             font_info, block);
1312  BLOCK_INPUT;
1314 #ifdef NS_IMPL_COCOA
1315   if (firstTime)
1316     {
1317       firstTime = 0;
1318       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1319     }
1320 #endif
1322   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1323   if (!unichars || !(font_info->glyphs[block]))
1324     abort ();
1326   /* create a string containing all unicode characters in this block */
1327   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1328     if (idx < 0xD800 || idx > 0xDFFF)
1329       unichars[i] = idx;
1330     else
1331       unichars[i] = 0xFEFF;
1332   unichars[0x100] = 0;
1334   {
1335 #ifdef NS_IMPL_COCOA
1336     NSString *allChars = [[NSString alloc]
1337                                initWithCharactersNoCopy: unichars
1338                                                  length: 0x100
1339                                            freeWhenDone: NO];
1340     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1341     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1342     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1343     NSUInteger gInd =0, cInd =0;
1345     [glyphStorage setString: allChars font: font_info->nsfont];
1346     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1347                         desiredNumberOfCharacters: glyphStorage->maxChar
1348                                        glyphIndex: &gInd characterIndex: &cInd];
1349 #endif
1350     glyphs = font_info->glyphs[block];
1351     for (i =0; i<0x100; i++, glyphs++)
1352       {
1353 #ifdef NS_IMPL_GNUSTEP
1354         g = unichars[i];
1355 #else
1356         g = glyphStorage->cglyphs[i];
1357         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1358         if (g > numGlyphs)
1359           g = 0xFFFF; /* hopefully unused... */
1360 #endif
1361         *glyphs = g;
1362       }
1364 #ifdef NS_IMPL_COCOA
1365     [allChars release];
1366 #endif
1367   }
1369   UNBLOCK_INPUT;
1370   xfree (unichars);
1374 /* Determine and cache metrics for corresponding glyph codes in given
1375    hi-byte block of 256. */
1376 static void
1377 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1379   unsigned int i, g;
1380   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1381   NSFont *sfont;
1382   struct font_metrics *metrics;
1384   if (NSFONT_TRACE)
1385     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1386             font_info, block);
1388 #ifdef NS_IMPL_GNUSTEP
1389   /* not implemented yet (as of startup 0.18), so punt */
1390   if (numGlyphs == 0)
1391     numGlyphs = 0x10000;
1392 #endif
1394  BLOCK_INPUT;
1395  sfont = [font_info->nsfont screenFont];
1397   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1398   memset (font_info->metrics[block], 0, 0x100 * sizeof (struct font_metrics));
1399   if (!(font_info->metrics[block]))
1400     abort ();
1402   metrics = font_info->metrics[block];
1403   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1404     {
1405       float w, lb, rb;
1406       NSRect r = [sfont boundingRectForGlyph: g];
1408       w = max ([sfont advancementForGlyph: g].width, 2.0);
1409       metrics->width = lrint (w);
1411       lb = r.origin.x;
1412       rb = r.size.width - w;
1413       if (lb < 0)
1414         metrics->lbearing = round (lb);
1415       if (font_info->ital)
1416         rb += 0.22 * font_info->height;
1417       metrics->rbearing = lrint (w + rb);
1419       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1420  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1421       metrics->ascent = r.size.height - metrics->descent;
1422 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1423     }
1424   UNBLOCK_INPUT;
1428 #ifdef NS_IMPL_COCOA
1429 /* helper for font glyph setup */
1430 @implementation EmacsGlyphStorage
1432 - init
1434   return [self initWithCapacity: 1024];
1437 - initWithCapacity: (unsigned long) c
1439   self = [super init];
1440   maxChar = 0;
1441   maxGlyph = 0;
1442   dict = [NSMutableDictionary new];
1443   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1444   return self;
1447 - (void) dealloc
1449   if (attrStr != nil)
1450     [attrStr release];
1451   [dict release];
1452   xfree (cglyphs);
1453   [super dealloc];
1456 - (void) setString: (NSString *)str font: (NSFont *)font
1458   [dict setObject: font forKey: NSFontAttributeName];
1459   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1460   maxChar = [str length];
1461   maxGlyph = 0;
1464 /* NSGlyphStorage protocol */
1465 - (NSUInteger)layoutOptions
1467   return 0;
1470 - (NSAttributedString *)attributedString
1472   return attrStr;
1475 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1476         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1477         characterIndex: (NSUInteger)charIndex
1479   len = glyphIndex+length;
1480   for (i =glyphIndex; i<len; i++)
1481     cglyphs[i] = glyphs[i-glyphIndex];
1482   if (len > maxGlyph)
1483     maxGlyph = len;
1486 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1487         forGlyphAtIndex: (NSUInteger)glyphIndex
1489   return;
1492 @end
1493 #endif /* NS_IMPL_COCOA */
1496 /* Debugging */
1497 void
1498 ns_dump_glyphstring (struct glyph_string *s)
1500   int i;
1502   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1503 "overlap = %d, bg_filled = %d:",
1504            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1505            s->row->overlapping_p, s->background_filled_p);
1506   for (i =0; i<s->nchars; i++)
1507     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1508   fprintf (stderr, "\n");
1512 void
1513 syms_of_nsfont (void)
1515   nsfont_driver.type = Qns;
1516   register_font_driver (&nsfont_driver, NULL);
1517   DEFSYM (Qapple, "apple");
1518   DEFSYM (Qroman, "roman");
1519   DEFSYM (Qmedium, "medium");
1520   DEFVAR_LISP ("ns-reg-to-script", &Vns_reg_to_script,
1521                doc: /* Internal use: maps font registry to unicode script. */);
1524 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae