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