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