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