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