gnus-start-draft-setup: Move doc string forward.
[emacs.git] / src / nsfont.m
blob115986774d83f8a6265e27c96636a07762e31e4b
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"
41 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
42 #ifdef NS_IMPL_GNUSTEP
43 #import <AppKit/NSFontDescriptor.h>
44 #endif
46 #define NSFONT_TRACE 0
48 extern Lisp_Object Qns;
49 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
50 static Lisp_Object Vns_reg_to_script;
51 static Lisp_Object Qapple, Qroman, Qmedium;
52 extern Lisp_Object Qappend;
53 extern Lisp_Object ns_antialias_text;
54 extern float ns_antialias_threshold;
55 extern int ns_tmp_flags;
56 extern struct nsfont_info *ns_tmp_font;
58 /* font glyph and metrics caching functions, implemented at end */
59 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
60                               unsigned char block);
61 static void ns_glyph_metrics (struct nsfont_info *font_info,
62                               unsigned char block);
65 /* ==========================================================================
67     Utilities
69    ========================================================================== */
72 /* Replace spaces w/another character so emacs core font parsing routines
73    aren't thrown off. */
74 static void
75 ns_escape_name (char *name)
77   int i =0, len =strlen (name);
78   for ( ; i<len; i++)
79     if (name[i] == ' ')
80       name[i] = '_';
84 /* Reconstruct spaces in a font family name passed through emacs. */
85 static void
86 ns_unescape_name (char *name)
88   int i =0, len =strlen (name);
89   for ( ; i<len; i++)
90     if (name[i] == '_')
91       name[i] = ' ';
95 /* Extract family name from a font spec. */
96 static NSString *
97 ns_get_family (Lisp_Object font_spec)
99   Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
100   if (NILP (tem))
101       return nil;
102   else
103     {
104       char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
105       NSString *family;
106       ns_unescape_name (tmp);
107       family = [NSString stringWithUTF8String: tmp];
108       free (tmp);
109       return family;
110     }
114 /* Return 0 if attr not set, else value (which might also be 0).
115    On Leopard 0 gets returned even on descriptors where the attribute
116    was never set, so there's no way to distinguish between unspecified
117    and set to not have.  Callers should assume 0 means unspecified. */
118 static float
119 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
121     NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
122     NSNumber *val = [tdict objectForKey: trait];
123     return val == nil ? 0.0 : [val floatValue];
127 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
128    to NSFont descriptor.  Information under extra only needed for matching. */
129 #define STYLE_REF 100
130 static NSFontDescriptor
131 *ns_spec_to_descriptor(Lisp_Object font_spec)
133     NSFontDescriptor *fdesc;
134     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
135     NSMutableDictionary *tdict = [NSMutableDictionary new];
136     NSString *family = ns_get_family (font_spec);
137     float n;
139     /* add each attr in font_spec to fdAttrs.. */
140     n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
141     if (n != -1 && n != STYLE_REF)
142         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
143                   forKey: NSFontWeightTrait];
144     n = min (FONT_SLANT_NUMERIC (font_spec), 200);
145     if (n != -1 && n != STYLE_REF)
146         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
147                   forKey: NSFontSlantTrait];
148     n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
149     if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
150         [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
151                   forKey: NSFontWidthTrait];
152     if ([tdict count] > 0)
153         [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
155     fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
156     if (family != nil)
157         fdesc = [fdesc fontDescriptorWithFamily: family];
158     return fdesc;
162 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
163 static Lisp_Object
164 ns_descriptor_to_entity (NSFontDescriptor *desc,
165                          Lisp_Object extra,
166                          const char *style)
168     Lisp_Object font_entity = font_make_entity ();
169     /*   NSString *psName = [desc postscriptName]; */
170     NSString *family = [desc objectForKey: NSFontFamilyAttribute];
171     unsigned int traits = [desc symbolicTraits];
172     char *escapedFamily;
174     /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
175     if (family == nil)
176       family = [desc objectForKey: NSFontNameAttribute];
177     if (family == nil)
178       family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
180     escapedFamily = strdup ([family UTF8String]);
181     ns_escape_name (escapedFamily);
183     ASET (font_entity, FONT_TYPE_INDEX, Qns);
184     ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
185     ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
186     ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
187     ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
189     FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
190                     traits & NSFontBoldTrait ? Qbold : Qmedium);
191 /*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
192                     make_number (100 + 100
193                         * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
194     FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
195                     traits & NSFontItalicTrait ? Qitalic : Qnormal);
196 /*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
197                     make_number (100 + 100
198                          * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
199     FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
200                     traits & NSFontCondensedTrait ? Qcondensed :
201                     traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
202 /*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
203                     make_number (100 + 100
204                          * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
206     ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
207     ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
208     ASET (font_entity, FONT_SPACING_INDEX,
209           make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
210               ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
212     ASET (font_entity, FONT_EXTRA_INDEX, extra);
213     ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
215     if (NSFONT_TRACE)
216       {
217         fprintf (stderr, "created font_entity:\n    ");
218         debug_print (font_entity);
219       }
221     free (escapedFamily);
222     return font_entity;
226 /* Default font entity. */
227 static Lisp_Object
228 ns_fallback_entity (void)
230   return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
231       fontDescriptor], Qnil, NULL);
235 /* Utility: get width of a char c in screen font sfont */
236 static float
237 ns_char_width (NSFont *sfont, int c)
239     float w;
240     NSString *cstr = [NSString stringWithFormat: @"%c", c];
241 #ifdef NS_IMPL_COCOA
242     NSGlyph glyph = [sfont glyphWithName: cstr];
243     if (glyph)
244       {
245         float w = [sfont advancementForGlyph: glyph].width;
246         if (w >= 1.5)
247             return w;
248       }
249 #endif
250     {
251       NSDictionary *attrsDictionary =
252         [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
253       w = [cstr sizeWithAttributes: attrsDictionary].width;
254     }
255     return max (w, 2.0);
259 /* Return whether set1 covers set2 to a reasonable extent given by pct.
260    We check, out of each 16 unicode char range containing chars in set2,
261    whether at least one character is present in set1.
262    This must be true for pct of the pairs to consider it covering. */
263 static BOOL
264 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
266     const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
267     const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
268     int i, off = 0, tot = 0;
270     for (i=0; i<4096; i++, bytes1++, bytes2++)
271         if (*bytes2)
272           {
273             tot++;
274             if (*bytes1 == 0)  // *bytes1 & *bytes2 != *bytes2
275                 off++;
276           }
277 //fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
278     return (float)off / tot < 1.0 - pct;
282 /* Convert :lang property to a script.  Use of :lang property by font backend
283    seems to be limited for now (2009/05) to ja, zh, and ko. */
284 static NSString
285 *ns_lang_to_script (Lisp_Object lang)
287     if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
288         return @"han";
289     /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
290              have more characters. */
291     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
292         return @"han";
293     else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
294         return @"hangul";
295     else
296         return @"";
300 /* Convert OTF 4-letter script code to emacs script name.  (Why can't
301    everyone just use some standard unicode names for these?) */
302 static NSString
303 *ns_otf_to_script (Lisp_Object otf)
305     Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
306     return CONSP (script)
307         ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))]
308         : @"";
312 /* Convert a font registry, such as  */
313 static NSString
314 *ns_registry_to_script (char *reg)
316     Lisp_Object script, r, rts = Vns_reg_to_script;
317     while CONSP (rts)
318       {
319         r = XCAR (XCAR (rts));
320         if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
321           {
322             script = XCDR (XCAR (rts));
323             return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
324           }
325         rts = XCDR (rts);
326       }
327     return  @"";
331 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
332    plus registry regular property, for something that can be mapped to a
333    unicode script.  Empty string returned if no script spec found. */
334 static NSString
335 *ns_get_req_script (Lisp_Object font_spec)
337     Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
338     Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
340     /* The extra-bundle properties have priority. */
341     for ( ; CONSP (extra); extra = XCDR (extra))
342       {
343         Lisp_Object tmp = XCAR (extra);
344         if (CONSP (tmp))
345           {
346             Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
347             if (EQ (key, QCscript) && SYMBOLP (val))
348                 return [NSString stringWithUTF8String:
349                             SDATA (SYMBOL_NAME (val))];
350             if (EQ (key, QClang) && SYMBOLP (val))
351                 return ns_lang_to_script (val);
352             if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
353                 return ns_otf_to_script (val);
354           }
355       }
357     /* If we get here, check the charset portion of the registry. */
358     if (! NILP (reg))
359       {
360         /* XXX: iso10646 is passed in for non-ascii latin-1 characters
361            (which causes box rendering if we don't treat it like iso8858-1)
362            but also for ascii (which causes unnecessary font substitution). */
363 #if 0
364         if (EQ (reg, Qiso10646_1))
365           reg = Qiso8859_1;
366 #endif
367         return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
368       }
370     return @"";
374 /* This small function is static in fontset.c.  If it can be made public for
375    all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
376 static void
377 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
379     if (EQ (XCAR (arg), val))
380       {
381         if (CONSP (range))
382           XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
383         else
384           XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
385       }
389 /* Use the unicode range information in Vchar_script_table to convert a script
390    name into an NSCharacterSet. */
391 static NSCharacterSet
392 *ns_script_to_charset (NSString *scriptName)
394     NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
395     Lisp_Object script = intern ([scriptName UTF8String]);
396     Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
398     if (! NILP (Fmemq (script, script_list)))
399       {
400         Lisp_Object ranges, range_list;
402         ranges = Fcons (script, Qnil);
403         map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
404                         ranges);
405         range_list = Fnreverse (XCDR (ranges));
406         if (! NILP (range_list))
407           {
408             for (; CONSP (range_list); range_list = XCDR (range_list))
409               {
410                 int start = XINT (XCAR (XCAR (range_list)));
411                 int end = XINT (XCDR (XCAR (range_list)));
412                 if (NSFONT_TRACE)
413                     debug_print (XCAR (range_list));
414                 if (end < 0x10000)
415                     [charset addCharactersInRange:
416                         NSMakeRange (start, end-start)];
417               }
418           }
419       }
420     return charset;
424 /* Return an array of font families containing characters for the given
425    script, for the given coverage criterion, including at least LastResort.
426    Results are cached by script for faster access.
427    If none are found, we reduce the percentage and try again, until 5%.
428    This provides a font with at least some characters if such can be found.
429    We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
430    (b) need approximate match as fonts covering full unicode ranges are rare. */
431 static NSSet
432 *ns_get_covering_families (NSString *script, float pct)
434     static NSMutableDictionary *scriptToFamilies = nil;
435     NSMutableSet *families;
437     if (NSFONT_TRACE)
438         NSLog(@"Request covering families for script: '%@'", script);
440     if (scriptToFamilies == nil)
441         scriptToFamilies = [[NSMutableDictionary alloc] init];
443     if ((families = [scriptToFamilies objectForKey: script]) == nil)
444       {
445         NSFontManager *fontMgr = [NSFontManager sharedFontManager];
446         NSArray *allFamilies = [fontMgr availableFontFamilies];
448         if ([script length] == 0)
449             families = [NSMutableSet setWithArray: allFamilies];
450         else
451           {
452             NSCharacterSet *charset = ns_script_to_charset (script);
453             NSString *family;
454             families = [NSMutableSet setWithCapacity: 10];
455             while (1)
456               {
457                 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
458                 while (family = [allFamiliesEnum nextObject])
459                   {
460                     NSCharacterSet *fset = [[fontMgr fontWithFamily: family
461                         traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
462                     /* Some fonts on OS X, maybe many on GNUstep, return nil. */
463                     if (fset == nil)
464                       fset = [NSCharacterSet characterSetWithRange:
465                                                NSMakeRange (0, 127)];
466                     if (ns_charset_covers(fset, charset, pct))
467                         [families addObject: family];
468                   }
469                 pct -= 0.2;
470                 if ([families count] > 0 || pct < 0.05)
471                     break;
472               }
473           }
474 #ifdef NS_IMPL_COCOA
475         if ([families count] == 0)
476             [families addObject: @"LastResort"];
477 #endif
478         [scriptToFamilies setObject: families forKey: script];
479       }
481     if (NSFONT_TRACE)
482         NSLog(@"    returning %d families", [families count]);
483     return families;
487 /* Implementation for list() and match().  List() can return nil, match()
488 must return something.  Strategy is to drop family name from attribute
489 matching set for match. */
490 static Lisp_Object
491 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
493     Lisp_Object tem, list = Qnil;
494     NSFontDescriptor *fdesc, *desc;
495     NSMutableSet *fkeys;
496     NSArray *matchingDescs;
497     NSEnumerator *dEnum;
498     NSString *family;
499     NSSet *cFamilies;
500     BOOL foundItal = NO;
502     if (NSFONT_TRACE)
503       {
504         fprintf (stderr, "nsfont: %s for fontspec:\n    ",
505                  (isMatch ? "match" : "list"));
506         debug_print (font_spec);
507       }
509     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
511     fdesc = ns_spec_to_descriptor (font_spec);
512     fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
513     if (isMatch)
514         [fkeys removeObject: NSFontFamilyAttribute];
516     matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
517     if (NSFONT_TRACE)
518         NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
519               [matchingDescs count]);
521     for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
522       {
523         if (![cFamilies containsObject:
524                  [desc objectForKey: NSFontFamilyAttribute]])
525             continue;
526         tem = ns_descriptor_to_entity (desc,
527                                          AREF (font_spec, FONT_EXTRA_INDEX),
528                                        NULL);
529         if (isMatch)
530           return tem;
531         list = Fcons (tem, list);
532         if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
533             foundItal = YES;
534       }
536     /* Add synthItal member if needed. */
537     family = [fdesc objectForKey: NSFontFamilyAttribute];
538     if (family != nil && !foundItal && XINT (Flength (list)) > 0)
539       {
540         NSFontDescriptor *sDesc = [[[NSFontDescriptor new]
541             fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
542             fontDescriptorWithFamily: family];
543         list = Fcons (ns_descriptor_to_entity (sDesc,
544                                          AREF (font_spec, FONT_EXTRA_INDEX),
545                                          "synthItal"), list);
546       }
548     /* Return something if was a match and nothing found. */
549     if (isMatch)
550       return ns_fallback_entity ();
552     if (NSFONT_TRACE)
553         fprintf (stderr, "    Returning %ld entities.\n",
554                  (long) XINT (Flength (list)));
556     return list;
561 /* ==========================================================================
563     Font driver implementation
565    ========================================================================== */
568 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
569 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
570 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
571 static Lisp_Object nsfont_list_family (Lisp_Object frame);
572 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
573                                  int pixel_size);
574 static void nsfont_close (FRAME_PTR f, struct font *font);
575 static int nsfont_has_char (Lisp_Object entity, int c);
576 static unsigned int nsfont_encode_char (struct font *font, int c);
577 static int nsfont_text_extents (struct font *font, unsigned int *code,
578                                 int nglyphs, struct font_metrics *metrics);
579 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
580                         int with_background);
582 struct font_driver nsfont_driver =
583   {
584     0,                          /* Qns */
585     1,                          /* case sensitive */
586     nsfont_get_cache,
587     nsfont_list,
588     nsfont_match,
589     nsfont_list_family,
590     NULL,                       /*free_entity */
591     nsfont_open,
592     nsfont_close,
593     NULL,                       /* prepare_face */
594     NULL,                       /* done_face */
595     nsfont_has_char,
596     nsfont_encode_char,
597     nsfont_text_extents,
598     nsfont_draw,
599     /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
600                  anchor_point, otf_capability, otf_driver,
601                  start_for_frame, end_for_frame, shape */
602   };
605 /* Return a cache of font-entities on FRAME.  The cache must be a
606    cons whose cdr part is the actual cache area.  */
607 static Lisp_Object
608 nsfont_get_cache (FRAME_PTR frame)
610   Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
611   return (dpyinfo->name_list_element);
615 /* List fonts exactly matching with FONT_SPEC on FRAME.  The value is a
616    **list** of font-entities.  This and match () are sole APIs that allocate
617    font-entities.  Properties to be considered (2009/05/19) are:
618    regular: foundry, family, adstyle, registry
619    extended: script, lang, otf
620   "Extended" properties are not part of the vector but get stored as
621    lisp properties under FONT_EXTRA_INDEX.
623    The returned entities should have type set (to 'ns), plus the following:
624    foundry, family, adstyle, registry,
625    weight, slant, width, size (0 if scalable),
626    dpi, spacing, avgwidth (0 if scalable)  */
627 static Lisp_Object
628 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
630     return ns_findfonts (font_spec, NO);
634 /* Return a font entity most closely maching with FONT_SPEC on
635    FRAME.  The closeness is determined by the font backend, thus
636    `face-font-selection-order' is ignored here.
637    Properties to be considered are same as for list(). */
638 static Lisp_Object
639 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
641     return ns_findfonts(font_spec, YES);
645 /* List available families.  The value is a list of family names
646    (symbols). */
647 static Lisp_Object
648 nsfont_list_family (Lisp_Object frame)
650   Lisp_Object list = Qnil;
651   NSEnumerator *families =
652     [[[NSFontManager sharedFontManager] availableFontFamilies]
653       objectEnumerator];
654   NSString *family;
655   while (family = [families nextObject])
656       list = Fcons (intern ([family UTF8String]), list);
657   /* FIXME: escape the name? */
659   if (NSFONT_TRACE)
660     fprintf (stderr, "nsfont: list families returning %ld entries\n",
661             (long) XINT (Flength (list)));
663   return list;
667 /* Open a font specified by FONT_ENTITY on frame F.  If the font is
668    scalable, open it with PIXEL_SIZE.  */
669 static Lisp_Object
670 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
672   BOOL synthItal;
673   unsigned int traits = 0;
674   struct nsfont_info *font_info;
675   struct font *font;
676   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
677   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
678   NSString *family;
679   NSFont *nsfont, *sfont;
680   Lisp_Object tem;
681   NSRect brect;
682   Lisp_Object font_object;
683   int i;
684   int fixLeopardBug;
685   static NSMutableDictionary *fontCache = nil;
686   NSNumber *cached;
688   /* 2008/03/08: The same font may end up being requested for different
689      entities, due to small differences in numeric values or other issues,
690      or for different copies of the same entity.  Therefore we cache to
691      avoid creating multiple struct font objects (with metrics cache, etc.)
692      for the same NSFont object. */
693   if (fontCache == nil)
694     fontCache = [[NSMutableDictionary alloc] init];
696   if (NSFONT_TRACE)
697     {
698       fprintf (stderr, "nsfont: open size %d of fontentity:\n    ", pixel_size);
699       debug_print (font_entity);
700     }
702   if (pixel_size <= 0)
703     {
704       /* try to get it out of frame params */
705         Lisp_Object tem = get_frame_param (f, Qfontsize);
706         pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
707     }
709   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
710   synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
711                                        9);
712   family = ns_get_family (font_entity);
713   if (family == nil)
714     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
715   /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
716      when setting family in ns_spec_to_descriptor(). */
717   if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
718       traits |= NSBoldFontMask;
719   if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
720       traits |= NSItalicFontMask;
722   /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
723   fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
724   nsfont = [fontMgr fontWithFamily: family
725                             traits: traits weight: fixLeopardBug
726                               size: pixel_size];
727   /* if didn't find, try synthetic italic */
728   if (nsfont == nil && synthItal)
729     {
730       nsfont = [fontMgr fontWithFamily: family
731                                 traits: traits & ~NSItalicFontMask
732                                 weight: fixLeopardBug size: pixel_size];
733     }
734 #ifdef NS_IMPL_COCOA
735   /* LastResort not really a family */
736   if (nsfont == nil && [@"LastResort" isEqualToString: family])
737       nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
738 #endif
740   if (nsfont == nil)
741     {
742       message_with_string ("*** Warning: font in family '%s' not found",
743                           build_string ([family UTF8String]), 1);
744       nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
745     }
747   if (NSFONT_TRACE)
748     NSLog (@"%@\n", nsfont);
750   /* Check the cache */
751   cached = [fontCache objectForKey: nsfont];
752   if (cached != nil && !synthItal)
753     {
754       if (NSFONT_TRACE)
755         fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
756       /* FIXME: Cast from (unsigned long) to Lisp_Object. */
757       XHASH (font_object) = [cached unsignedLongValue];
758       return font_object;
759     }
760   else
761     {
762       font_object = font_make_object (VECSIZE (struct nsfont_info),
763                                       font_entity, pixel_size);
764       if (!synthItal)
765         [fontCache setObject: [NSNumber numberWithUnsignedLong:
766                                           (unsigned long) XHASH (font_object)]
767                       forKey: nsfont];
768     }
770   font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
771   font = (struct font *) font_info;
772   if (!font)
773     return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
775   font_info->glyphs = (unsigned short **)
776     xmalloc (0x100 * sizeof (unsigned short *));
777   font_info->metrics = (struct font_metrics **)
778     xmalloc (0x100 * sizeof (struct font_metrics *));
779   if (!font_info->glyphs || !font_info->metrics)
780     return Qnil;
781   memset (font_info->glyphs, 0, 0x100 * sizeof (unsigned short *));
782   memset (font_info->metrics, 0, 0x100 * sizeof (struct font_metrics *));
784   BLOCK_INPUT;
786   /* for metrics */
787   sfont = [nsfont screenFont];
788   if (sfont == nil)
789     sfont = nsfont;
791   /* non-metric backend font struct fields */
792   font = (struct font *) font_info;
793   font->pixel_size = [sfont pointSize];
794   font->driver = &nsfont_driver;
795   font->encoding_type = FONT_ENCODING_NOT_DECIDED;
796   font->encoding_charset = -1;
797   font->repertory_charset = -1;
798   font->default_ascent = 0;
799   font->vertical_centering = 0;
800   font->baseline_offset = 0;
801   font->relative_compose = 0;
802   font->font_encoder = NULL;
804   font->props[FONT_FORMAT_INDEX] = Qns;
805   font->props[FONT_FILE_INDEX] = Qnil;
807   {
808     double expand, hshrink;
809     float full_height, min_height, hd;
810     const char *fontName = [[nsfont fontName] UTF8String];
811     int len = strlen (fontName);
813 #ifdef NS_IMPL_GNUSTEP
814     font_info->nsfont = sfont;
815 #else
816     font_info->nsfont = nsfont;
817 #endif
818     [font_info->nsfont retain];
820     /* set up ns_font (defined in nsgui.h) */
821     font_info->name = (char *)xmalloc (strlen (fontName)+1);
822     strcpy (font_info->name, fontName);
823     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
824     font_info->ital =
825       synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
827     /* Metrics etc.; some fonts return an unusually large max advance, so we
828        only use it for fonts that have wide characters. */
829     font_info->width = ([sfont numberOfGlyphs] > 2000) ?
830       [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
832     brect =  [sfont boundingRectForFont];
833     full_height = brect.size.height;
834     min_height = [sfont ascender] - [sfont descender];
835     hd = full_height - min_height;
837     /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
838     expand = 0.0;
839     hshrink = 1.0;
841     font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
842     font_info->underwidth = [sfont underlineThickness];
843     font_info->size = font->pixel_size;
844     font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
846     /* max bounds */
847     font_info->max_bounds.ascent =
848       lrint (hshrink * [sfont ascender] + expand * hd/2);
849     /* [sfont descender] is usually negative.  Use floor to avoid
850        clipping descenders. */
851     font_info->max_bounds.descent =
852       -lrint (floor(hshrink* [sfont descender] - expand*hd/2));
853     font_info->height =
854       font_info->max_bounds.ascent + font_info->max_bounds.descent;
855     font_info->max_bounds.width = lrint (font_info->width);
856     font_info->max_bounds.lbearing = lrint (brect.origin.x);
857     font_info->max_bounds.rbearing =
858       lrint (brect.size.width - font_info->width);
860 #ifdef NS_IMPL_COCOA
861     /* set up synthItal and the CG font */
862     font_info->synthItal = synthItal;
863     {
864       ATSFontRef atsFont = ATSFontFindFromPostScriptName
865         ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
867       if (atsFont == kATSFontRefUnspecified)
868         {
869           /* see if we can get it by dropping italic (then synthesizing) */
870           atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
871               [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
872                 fontName], kATSOptionFlagsDefault);
873           if (atsFont != kATSFontRefUnspecified)
874               font_info->synthItal = YES;
875           else
876             {
877               /* last resort fallback */
878               atsFont = ATSFontFindFromPostScriptName
879                 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
880             }
881         }
882       font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
883     }
884 #endif
886     /* set up metrics portion of font struct */
887     font->ascent = lrint([sfont ascender]);
888     font->descent = -lrint(floor([sfont descender]));
889     font->min_width = ns_char_width(sfont, '|');
890     font->space_width = lrint (ns_char_width (sfont, ' '));
891     font->average_width = lrint (font_info->width);
892     font->max_width = lrint (font_info->max_bounds.width);
893     font->height = lrint (font_info->height);
894     font->underline_position = lrint (font_info->underpos);
895     font->underline_thickness = lrint (font_info->underwidth);
897     font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
898     font->props[FONT_FULLNAME_INDEX] =
899       make_unibyte_string (font_info->name, strlen (font_info->name));
900   }
901   UNBLOCK_INPUT;
903   return font_object;
907 /* Close FONT on frame F. */
908 static void
909 nsfont_close (FRAME_PTR f, struct font *font)
911   struct nsfont_info *font_info = (struct nsfont_info *)font;
912   int i;
914   /* FIXME: this occurs apparently due to same failure to detect same font
915             that causes need for cache in nsfont_open () */
916   if (!font_info)
917       return;
919   for (i =0; i<0x100; i++)
920     {
921       xfree (font_info->glyphs[i]);
922       xfree (font_info->metrics[i]);
923     }
924   [font_info->nsfont release];
925 #ifdef NS_IMPL_COCOA
926   CGFontRelease (font_info->cgfont);
927 #endif
928   xfree (font_info->name);
929   xfree (font_info);
933 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
934    return 1.  If not, return 0.  If a font must be opened to check
935    it, return -1. */
936 static int
937 nsfont_has_char (Lisp_Object entity, int c)
939   return -1;
943 /* Return a glyph code of FONT for character C (Unicode code point).
944    If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
945 static unsigned int
946 nsfont_encode_char (struct font *font, int c)
948   struct nsfont_info *font_info = (struct nsfont_info *)font;
949   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
950   unsigned short g;
952   if (c > 0xFFFF)
953     return FONT_INVALID_CODE;
955   /* did we already cache this block? */
956   if (!font_info->glyphs[high])
957     ns_uni_to_glyphs (font_info, high);
959   g = font_info->glyphs[high][low];
960   return g == 0xFFFF ? FONT_INVALID_CODE : g;
964 /* Perform the size computation of glyphs of FONT and fill in members
965    of METRICS.  The glyphs are specified by their glyph codes in
966    CODE (length NGLYPHS). */
967 static int
968 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
969                      struct font_metrics *metrics)
971   struct nsfont_info *font_info = (struct nsfont_info *)font;
972   struct font_metrics *pcm;
973   unsigned char high, low;
974   int totalWidth = 0;
975   int i;
977   memset (metrics, 0, sizeof (struct font_metrics));
979   for (i =0; i<nglyphs; i++)
980     {
981       /* get metrics for this glyph, filling cache if need be */
982       /* TODO: get metrics for whole string from an NSLayoutManager
983                (if not too slow) */
984       high = (code[i] & 0xFF00) >> 8;
985       low = code[i] & 0x00FF;
986       if (!font_info->metrics[high])
987         ns_glyph_metrics (font_info, high);
988       pcm = &(font_info->metrics[high][low]);
990       if (metrics->lbearing > totalWidth + pcm->lbearing)
991         metrics->lbearing = totalWidth + pcm->lbearing;
992       if (metrics->rbearing < totalWidth + pcm->rbearing)
993         metrics->rbearing = totalWidth + pcm->rbearing;
994       if (metrics->ascent < pcm->ascent)
995         metrics->ascent = pcm->ascent;
996       if (metrics->descent < pcm->descent)
997         metrics->descent = pcm->descent;
999       totalWidth += pcm->width;
1000     }
1002   metrics->width = totalWidth;
1004   return totalWidth; /* not specified in doc, but xfont.c does it */
1008 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1009    position of frame F with S->FACE and S->GC.  If WITH_BACKGROUND
1010    is nonzero, fill the background in advance.  It is assured that
1011    WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1012 static int
1013 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1014              int with_background)
1015 /* NOTE: focus and clip must be set
1016      also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1018   static char cbuf[1024];
1019   char *c = cbuf;
1020 #ifdef NS_IMPL_GNUSTEP
1021   static float advances[1024];
1022   float *adv = advances;
1023 #else
1024   static CGSize advances[1024];
1025   CGSize *adv = advances;
1026 #endif
1027   struct face *face;
1028   NSRect r;
1029   struct nsfont_info *font = ns_tmp_font;
1030   NSColor *col, *bgCol;
1031   unsigned short *t = s->char2b;
1032   int i, len;
1033   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1034   int end = isComposite ? s->cmp_to : s->nchars;
1036   /* Select face based on input flags */
1037   switch (ns_tmp_flags)
1038     {
1039     case NS_DUMPGLYPH_CURSOR:
1040       face = s->face;
1041       break;
1042     case NS_DUMPGLYPH_MOUSEFACE:
1043       face = FACE_FROM_ID (s->f,
1044                            FRAME_NS_DISPLAY_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     return to-from;
1215   }
1217 #else  /* NS_IMPL_COCOA */
1218   {
1219     CGContextRef gcontext =
1220       [[NSGraphicsContext currentContext] graphicsPort];
1221     static CGAffineTransform fliptf;
1222     static BOOL firstTime = YES;
1224     if (firstTime)
1225       {
1226         firstTime = NO;
1227         fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1228       }
1230     CGContextSaveGState (gcontext);
1232     fliptf.c =  font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1234     CGContextSetFont (gcontext, font->cgfont);
1235     CGContextSetFontSize (gcontext, font->size);
1236     if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1237       CGContextSetShouldAntialias (gcontext, 0);
1238     else
1239       CGContextSetShouldAntialias (gcontext, 1);
1241     CGContextSetTextMatrix (gcontext, fliptf);
1243     if (bgCol != nil)
1244       {
1245         /* foreground drawing; erase first to avoid overstrike */
1246         [bgCol set];
1247         CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1248         CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1249         CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1250         CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1251       }
1253     if (face->underline_p)
1254       {
1255         if (face->underline_color != 0)
1256           [ns_lookup_indexed_color (face->underline_color, s->f) set];
1257         else
1258           [col set];
1259         CGContextBeginPath (gcontext);
1260         CGContextMoveToPoint (gcontext,
1261                               r.origin.x, r.origin.y + font->underpos);
1262         CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1263                                 r.origin.y + font->underpos);
1264         CGContextStrokePath (gcontext);
1265         if (face->underline_color != 0)
1266           [col set];
1267       }
1268     else
1269       [col set];
1271     CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1272     CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1273                                     advances, len);
1275     if (face->overstrike)
1276       {
1277         CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1278         CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1279                                         advances, len);
1280       }
1282     CGContextRestoreGState (gcontext);
1283     return;
1284   }
1285 #endif  /* NS_IMPL_COCOA */
1291 /* ==========================================================================
1293     Font glyph and metrics caching functions
1295    ========================================================================== */
1297 /* Find and cache corresponding glyph codes for unicode values in given
1298    hi-byte block of 256. */
1299 static void
1300 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1302 #ifdef NS_IMPL_COCOA
1303   static EmacsGlyphStorage *glyphStorage;
1304   static char firstTime = 1;
1305 #endif
1306   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1307   unsigned int i, g, idx;
1308   unsigned short *glyphs;
1310   if (NSFONT_TRACE)
1311     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1312             font_info, block);
1314  BLOCK_INPUT;
1316 #ifdef NS_IMPL_COCOA
1317   if (firstTime)
1318     {
1319       firstTime = 0;
1320       glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1321     }
1322 #endif
1324   font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1325   if (!unichars || !(font_info->glyphs[block]))
1326     abort ();
1328   /* create a string containing all unicode characters in this block */
1329   for (idx = block<<8, i =0; i<0x100; idx++, i++)
1330     if (idx < 0xD800 || idx > 0xDFFF)
1331       unichars[i] = idx;
1332     else
1333       unichars[i] = 0xFEFF;
1334   unichars[0x100] = 0;
1336   {
1337 #ifdef NS_IMPL_COCOA
1338     NSString *allChars = [[NSString alloc]
1339                                initWithCharactersNoCopy: unichars
1340                                                  length: 0x100
1341                                            freeWhenDone: NO];
1342     NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1343     /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1344     unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1345     NSUInteger gInd =0, cInd =0;
1347     [glyphStorage setString: allChars font: font_info->nsfont];
1348     [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1349                         desiredNumberOfCharacters: glyphStorage->maxChar
1350                                        glyphIndex: &gInd characterIndex: &cInd];
1351 #endif
1352     glyphs = font_info->glyphs[block];
1353     for (i =0; i<0x100; i++, glyphs++)
1354       {
1355 #ifdef NS_IMPL_GNUSTEP
1356         g = unichars[i];
1357 #else
1358         g = glyphStorage->cglyphs[i];
1359         /* TODO: is this a good check?  maybe need to use coveredChars.. */
1360         if (g > numGlyphs)
1361           g = 0xFFFF; /* hopefully unused... */
1362 #endif
1363         *glyphs = g;
1364       }
1366 #ifdef NS_IMPL_COCOA
1367     [allChars release];
1368 #endif
1369   }
1371   UNBLOCK_INPUT;
1372   xfree (unichars);
1376 /* Determine and cache metrics for corresponding glyph codes in given
1377    hi-byte block of 256. */
1378 static void
1379 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1381   unsigned int i, g;
1382   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1383   NSFont *sfont;
1384   struct font_metrics *metrics;
1386   if (NSFONT_TRACE)
1387     fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1388             font_info, block);
1390 #ifdef NS_IMPL_GNUSTEP
1391   /* not implemented yet (as of startup 0.18), so punt */
1392   if (numGlyphs == 0)
1393     numGlyphs = 0x10000;
1394 #endif
1396  BLOCK_INPUT;
1397  sfont = [font_info->nsfont screenFont];
1399   font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1400   memset (font_info->metrics[block], 0, 0x100 * sizeof (struct font_metrics));
1401   if (!(font_info->metrics[block]))
1402     abort ();
1404   metrics = font_info->metrics[block];
1405   for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1406     {
1407       float w, lb, rb;
1408       NSRect r = [sfont boundingRectForGlyph: g];
1410       w = max ([sfont advancementForGlyph: g].width, 2.0);
1411       metrics->width = lrint (w);
1413       lb = r.origin.x;
1414       rb = r.size.width - w;
1415       if (lb < 0)
1416         metrics->lbearing = round (lb);
1417       if (font_info->ital)
1418         rb += 0.22 * font_info->height;
1419       metrics->rbearing = lrint (w + rb);
1421       metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1422  /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1423       metrics->ascent = r.size.height - metrics->descent;
1424 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1425     }
1426   UNBLOCK_INPUT;
1430 #ifdef NS_IMPL_COCOA
1431 /* helper for font glyph setup */
1432 @implementation EmacsGlyphStorage
1434 - init
1436   return [self initWithCapacity: 1024];
1439 - initWithCapacity: (unsigned long) c
1441   self = [super init];
1442   maxChar = 0;
1443   maxGlyph = 0;
1444   dict = [NSMutableDictionary new];
1445   cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1446   return self;
1449 - (void) dealloc
1451   if (attrStr != nil)
1452     [attrStr release];
1453   [dict release];
1454   xfree (cglyphs);
1455   [super dealloc];
1458 - (void) setString: (NSString *)str font: (NSFont *)font
1460   [dict setObject: font forKey: NSFontAttributeName];
1461   attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1462   maxChar = [str length];
1463   maxGlyph = 0;
1466 /* NSGlyphStorage protocol */
1467 - (NSUInteger)layoutOptions
1469   return 0;
1472 - (NSAttributedString *)attributedString
1474   return attrStr;
1477 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1478         forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1479         characterIndex: (NSUInteger)charIndex
1481   len = glyphIndex+length;
1482   for (i =glyphIndex; i<len; i++)
1483     cglyphs[i] = glyphs[i-glyphIndex];
1484   if (len > maxGlyph)
1485     maxGlyph = len;
1488 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1489         forGlyphAtIndex: (NSUInteger)glyphIndex
1491   return;
1494 @end
1495 #endif /* NS_IMPL_COCOA */
1498 /* Debugging */
1499 void
1500 ns_dump_glyphstring (struct glyph_string *s)
1502   int i;
1504   fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1505 "overlap = %d, bg_filled = %d:",
1506            s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1507            s->row->overlapping_p, s->background_filled_p);
1508   for (i =0; i<s->nchars; i++)
1509     fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1510   fprintf (stderr, "\n");
1514 void
1515 syms_of_nsfont (void)
1517   nsfont_driver.type = Qns;
1518   register_font_driver (&nsfont_driver, NULL);
1519   DEFSYM (Qapple, "apple");
1520   DEFSYM (Qroman, "roman");
1521   DEFSYM (Qmedium, "medium");
1522   DEFVAR_LISP ("ns-reg-to-script", &Vns_reg_to_script,
1523                doc: /* Internal use: maps font registry to unicode script. */);
1526 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae