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