]> code.delx.au - gnu-emacs/blob - src/nsfont.m
Merge from trunk.
[gnu-emacs] / src / nsfont.m
1 /* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2 See font.h
3 Copyright (C) 2006-2012 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
19
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
21 */
22
23 /* This should be the first include, as it may set up #defines affecting
24 interpretation of even the system includes. */
25 #include <config.h>
26
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
31 #include "charset.h"
32 #include "frame.h"
33 #include "window.h"
34 #include "fontset.h"
35 #include "nsterm.h"
36 #include "frame.h"
37 #include "character.h"
38 #include "font.h"
39 #include "termchar.h"
40
41 /* TODO: Drop once we can assume gnustep-gui 0.17.1. */
42 #ifdef NS_IMPL_GNUSTEP
43 #import <AppKit/NSFontDescriptor.h>
44 #endif
45
46 #define NSFONT_TRACE 0
47
48 extern Lisp_Object Qns;
49 extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
50 static Lisp_Object Qapple, Qroman, Qmedium;
51 extern Lisp_Object Qappend;
52 extern float ns_antialias_threshold;
53 extern int ns_tmp_flags;
54 extern struct nsfont_info *ns_tmp_font;
55
56 static Lisp_Object Vfonts_in_cache;
57
58
59 /* font glyph and metrics caching functions, implemented at end */
60 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
61 unsigned char block);
62 static void ns_glyph_metrics (struct nsfont_info *font_info,
63 unsigned char block);
64
65
66 /* ==========================================================================
67
68 Utilities
69
70 ========================================================================== */
71
72
73 /* Replace spaces w/another character so emacs core font parsing routines
74 aren't thrown off. */
75 static void
76 ns_escape_name (char *name)
77 {
78 int i =0, len =strlen (name);
79 for ( ; i<len; i++)
80 if (name[i] == ' ')
81 name[i] = '_';
82 }
83
84
85 /* Reconstruct spaces in a font family name passed through emacs. */
86 static void
87 ns_unescape_name (char *name)
88 {
89 int i =0, len =strlen (name);
90 for ( ; i<len; i++)
91 if (name[i] == '_')
92 name[i] = ' ';
93 }
94
95
96 /* Extract family name from a font spec. */
97 static NSString *
98 ns_get_family (Lisp_Object font_spec)
99 {
100 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
101 if (NILP (tem))
102 return nil;
103 else
104 {
105 char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem)));
106 NSString *family;
107 ns_unescape_name (tmp);
108 family = [NSString stringWithUTF8String: tmp];
109 xfree (tmp);
110 return family;
111 }
112 }
113
114
115 /* Return 0 if attr not set, else value (which might also be 0).
116 On Leopard 0 gets returned even on descriptors where the attribute
117 was never set, so there's no way to distinguish between unspecified
118 and set to not have. Callers should assume 0 means unspecified. */
119 static float
120 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
121 {
122 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
123 NSNumber *val = [tdict objectForKey: trait];
124 return val == nil ? 0.0 : [val floatValue];
125 }
126
127
128 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
129 to NSFont descriptor. Information under extra only needed for matching. */
130 #define STYLE_REF 100
131 static NSFontDescriptor *
132 ns_spec_to_descriptor (Lisp_Object font_spec)
133 {
134 NSFontDescriptor *fdesc;
135 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
136 NSMutableDictionary *tdict = [NSMutableDictionary new];
137 NSString *family = ns_get_family (font_spec);
138 float n;
139
140 /* add each attr in font_spec to fdAttrs.. */
141 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
142 if (n != -1 && n != STYLE_REF)
143 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
144 forKey: NSFontWeightTrait];
145 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
146 if (n != -1 && n != STYLE_REF)
147 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
148 forKey: NSFontSlantTrait];
149 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
150 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
151 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
152 forKey: NSFontWidthTrait];
153 if ([tdict count] > 0)
154 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
155
156 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
157 if (family != nil)
158 {
159 fdesc = [fdesc fontDescriptorWithFamily: family];
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 float
243 ns_char_width (NSFont *sfont, int c)
244 {
245 float 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 float 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 < 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 / 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.0 - 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, strlen(SSDATA(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 = Fcons (script, Qnil);
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.2;
517 if ([families count] > 0 || pct < 0.05)
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 if (NSFONT_TRACE)
551 {
552 fprintf (stderr, "nsfont: %s for fontspec:\n ",
553 (isMatch ? "match" : "list"));
554 debug_print (font_spec);
555 }
556
557 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
558
559 fdesc = ns_spec_to_descriptor (font_spec);
560 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
561 if (isMatch)
562 [fkeys removeObject: NSFontFamilyAttribute];
563
564 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
565 if (NSFONT_TRACE)
566 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
567 [matchingDescs count]);
568
569 for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum nextObject]);)
570 {
571 if (![cFamilies containsObject:
572 [desc objectForKey: NSFontFamilyAttribute]])
573 continue;
574 tem = ns_descriptor_to_entity (desc,
575 AREF (font_spec, FONT_EXTRA_INDEX),
576 NULL);
577 if (isMatch)
578 return tem;
579 list = Fcons (tem, list);
580 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
581 foundItal = YES;
582 }
583
584 /* Add synthItal member if needed. */
585 family = [fdesc objectForKey: NSFontFamilyAttribute];
586 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
587 {
588 NSFontDescriptor *s1 = [NSFontDescriptor new];
589 NSFontDescriptor *sDesc
590 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
591 fontDescriptorWithFamily: family];
592 list = Fcons (ns_descriptor_to_entity (sDesc,
593 AREF (font_spec, FONT_EXTRA_INDEX),
594 "synthItal"), list);
595 [s1 release];
596 }
597
598 /* Return something if was a match and nothing found. */
599 if (isMatch)
600 return ns_fallback_entity ();
601
602 if (NSFONT_TRACE)
603 fprintf (stderr, " Returning %"pI"d entities.\n",
604 XINT (Flength (list)));
605
606 return list;
607 }
608
609
610
611 /* ==========================================================================
612
613 Font driver implementation
614
615 ========================================================================== */
616
617
618 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
619 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
620 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
621 static Lisp_Object nsfont_list_family (Lisp_Object frame);
622 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
623 int pixel_size);
624 static void nsfont_close (FRAME_PTR f, struct font *font);
625 static int nsfont_has_char (Lisp_Object entity, int c);
626 static unsigned int nsfont_encode_char (struct font *font, int c);
627 static int nsfont_text_extents (struct font *font, unsigned int *code,
628 int nglyphs, struct font_metrics *metrics);
629 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
630 bool with_background);
631
632 struct font_driver nsfont_driver =
633 {
634 0, /* Qns */
635 1, /* case sensitive */
636 nsfont_get_cache,
637 nsfont_list,
638 nsfont_match,
639 nsfont_list_family,
640 NULL, /*free_entity */
641 nsfont_open,
642 nsfont_close,
643 NULL, /* prepare_face */
644 NULL, /* done_face */
645 nsfont_has_char,
646 nsfont_encode_char,
647 nsfont_text_extents,
648 nsfont_draw,
649 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
650 anchor_point, otf_capability, otf_driver,
651 start_for_frame, end_for_frame, shape */
652 };
653
654
655 /* Return a cache of font-entities on FRAME. The cache must be a
656 cons whose cdr part is the actual cache area. */
657 static Lisp_Object
658 nsfont_get_cache (FRAME_PTR frame)
659 {
660 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
661 return (dpyinfo->name_list_element);
662 }
663
664
665 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
666 **list** of font-entities. This and match () are sole APIs that allocate
667 font-entities. Properties to be considered (2009/05/19) are:
668 regular: foundry, family, adstyle, registry
669 extended: script, lang, otf
670 "Extended" properties are not part of the vector but get stored as
671 lisp properties under FONT_EXTRA_INDEX.
672
673 The returned entities should have type set (to 'ns), plus the following:
674 foundry, family, adstyle, registry,
675 weight, slant, width, size (0 if scalable),
676 dpi, spacing, avgwidth (0 if scalable) */
677 static Lisp_Object
678 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
679 {
680 return ns_findfonts (font_spec, NO);
681 }
682
683
684 /* Return a font entity most closely matching with FONT_SPEC on
685 FRAME. The closeness is determined by the font backend, thus
686 `face-font-selection-order' is ignored here.
687 Properties to be considered are same as for list(). */
688 static Lisp_Object
689 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
690 {
691 return ns_findfonts(font_spec, YES);
692 }
693
694
695 /* List available families. The value is a list of family names
696 (symbols). */
697 static Lisp_Object
698 nsfont_list_family (Lisp_Object frame)
699 {
700 Lisp_Object list = Qnil;
701 NSEnumerator *families =
702 [[[NSFontManager sharedFontManager] availableFontFamilies]
703 objectEnumerator];
704 NSString *family;
705 while ((family = [families nextObject]))
706 list = Fcons (intern ([family UTF8String]), list);
707 /* FIXME: escape the name? */
708
709 if (NSFONT_TRACE)
710 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
711 XINT (Flength (list)));
712
713 return list;
714 }
715
716
717 /* Open a font specified by FONT_ENTITY on frame F. If the font is
718 scalable, open it with PIXEL_SIZE. */
719 static Lisp_Object
720 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
721 {
722 BOOL synthItal;
723 unsigned int traits = 0;
724 struct nsfont_info *font_info;
725 struct font *font;
726 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
727 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
728 NSString *family;
729 NSFont *nsfont, *sfont;
730 Lisp_Object tem;
731 NSRect brect;
732 Lisp_Object font_object;
733 int fixLeopardBug;
734 static NSMutableDictionary *fontCache = nil;
735 NSNumber *cached;
736
737 /* 2008/03/08: The same font may end up being requested for different
738 entities, due to small differences in numeric values or other issues,
739 or for different copies of the same entity. Therefore we cache to
740 avoid creating multiple struct font objects (with metrics cache, etc.)
741 for the same NSFont object. */
742 if (fontCache == nil)
743 fontCache = [[NSMutableDictionary alloc] init];
744
745 if (NSFONT_TRACE)
746 {
747 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
748 debug_print (font_entity);
749 }
750
751 if (pixel_size <= 0)
752 {
753 /* try to get it out of frame params */
754 Lisp_Object tem = get_frame_param (f, Qfontsize);
755 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
756 }
757
758 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
759 synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
760 9);
761 family = ns_get_family (font_entity);
762 if (family == nil)
763 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
764 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
765 when setting family in ns_spec_to_descriptor(). */
766 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
767 traits |= NSBoldFontMask;
768 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
769 traits |= NSItalicFontMask;
770
771 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
772 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
773 nsfont = [fontMgr fontWithFamily: family
774 traits: traits weight: fixLeopardBug
775 size: pixel_size];
776 /* if didn't find, try synthetic italic */
777 if (nsfont == nil && synthItal)
778 {
779 nsfont = [fontMgr fontWithFamily: family
780 traits: traits & ~NSItalicFontMask
781 weight: fixLeopardBug size: pixel_size];
782 }
783 #ifdef NS_IMPL_COCOA
784 /* LastResort not really a family */
785 if (nsfont == nil && [@"LastResort" isEqualToString: family])
786 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
787 #endif
788
789 if (nsfont == nil)
790 {
791 message_with_string ("*** Warning: font in family '%s' not found",
792 build_string ([family UTF8String]), 1);
793 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
794 }
795
796 if (NSFONT_TRACE)
797 NSLog (@"%@\n", nsfont);
798
799 /* Check the cache */
800 cached = [fontCache objectForKey: nsfont];
801 if (cached != nil && !synthItal)
802 {
803 if (NSFONT_TRACE)
804 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
805 XHASH (font_object) = [cached unsignedLongLongValue];
806 return font_object;
807 }
808 else
809 {
810 font_object = font_make_object (VECSIZE (struct nsfont_info),
811 font_entity, pixel_size);
812 if (!synthItal)
813 {
814 [fontCache setObject: [NSNumber
815 numberWithUnsignedLongLong:
816 (unsigned long long) XHASH (font_object)]
817 forKey: nsfont];
818 Vfonts_in_cache = Fcons (font_object, Vfonts_in_cache);
819 }
820 }
821
822 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
823 font = (struct font *) font_info;
824 if (!font)
825 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
826
827 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
828 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
829
830 block_input ();
831
832 /* for metrics */
833 sfont = [nsfont screenFont];
834 if (sfont == nil)
835 sfont = nsfont;
836
837 /* non-metric backend font struct fields */
838 font = (struct font *) font_info;
839 font->pixel_size = [sfont pointSize];
840 font->driver = &nsfont_driver;
841 font->encoding_charset = -1;
842 font->repertory_charset = -1;
843 font->default_ascent = 0;
844 font->vertical_centering = 0;
845 font->baseline_offset = 0;
846 font->relative_compose = 0;
847 font->font_encoder = NULL;
848
849 font->props[FONT_FORMAT_INDEX] = Qns;
850 font->props[FONT_FILE_INDEX] = Qnil;
851
852 {
853 const char *fontName = [[nsfont fontName] UTF8String];
854
855 /* The values specified by fonts are not always exact. For
856 * example, a 6x8 font could specify that the descender is
857 * -2.00000405... (represented by 0xc000000220000000). Without
858 * adjustment, the code below would round the descender to -3,
859 * resulting in a font that would be one pixel higher than
860 * intended. */
861 CGFloat adjusted_descender = [sfont descender] + 0.0001;
862
863 #ifdef NS_IMPL_GNUSTEP
864 font_info->nsfont = sfont;
865 #else
866 font_info->nsfont = nsfont;
867 #endif
868 [font_info->nsfont retain];
869
870 /* set up ns_font (defined in nsgui.h) */
871 font_info->name = xstrdup (fontName);
872 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
873 font_info->ital =
874 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
875
876 /* Metrics etc.; some fonts return an unusually large max advance, so we
877 only use it for fonts that have wide characters. */
878 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
879 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
880
881 brect = [sfont boundingRectForFont];
882
883 font_info->underpos = [sfont underlinePosition];
884 font_info->underwidth = [sfont underlineThickness];
885 font_info->size = font->pixel_size;
886
887 /* max bounds */
888 font_info->max_bounds.ascent = lrint ([sfont ascender]);
889 /* Descender is usually negative. Use floor to avoid
890 clipping descenders. */
891 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
892 font_info->height =
893 font_info->max_bounds.ascent + font_info->max_bounds.descent;
894 font_info->max_bounds.width = lrint (font_info->width);
895 font_info->max_bounds.lbearing = lrint (brect.origin.x);
896 font_info->max_bounds.rbearing =
897 lrint (brect.size.width - font_info->width);
898
899 #ifdef NS_IMPL_COCOA
900 /* set up synthItal and the CG font */
901 font_info->synthItal = synthItal;
902 {
903 ATSFontRef atsFont = ATSFontFindFromPostScriptName
904 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
905
906 if (atsFont == kATSFontRefUnspecified)
907 {
908 /* see if we can get it by dropping italic (then synthesizing) */
909 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
910 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
911 fontName], kATSOptionFlagsDefault);
912 if (atsFont != kATSFontRefUnspecified)
913 font_info->synthItal = YES;
914 else
915 {
916 /* last resort fallback */
917 atsFont = ATSFontFindFromPostScriptName
918 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
919 }
920 }
921 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
922 }
923 #endif
924
925 /* set up metrics portion of font struct */
926 font->ascent = lrint([sfont ascender]);
927 font->descent = -lrint(floor(adjusted_descender));
928 font->space_width = lrint (ns_char_width (sfont, ' '));
929 font->max_width = lrint (font_info->max_bounds.width);
930 font->min_width = font->space_width; /* Approximate. */
931 font->average_width = ns_ascii_average_width (sfont);
932
933 font->height = lrint (font_info->height);
934 font->underline_position = lrint (font_info->underpos);
935 font->underline_thickness = lrint (font_info->underwidth);
936
937 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
938 font->props[FONT_FULLNAME_INDEX] =
939 make_unibyte_string (font_info->name, strlen (font_info->name));
940 }
941 unblock_input ();
942
943 return font_object;
944 }
945
946
947 /* Close FONT on frame F. */
948 static void
949 nsfont_close (FRAME_PTR f, struct font *font)
950 {
951 struct nsfont_info *font_info = (struct nsfont_info *)font;
952 int i;
953
954 /* FIXME: this occurs apparently due to same failure to detect same font
955 that causes need for cache in nsfont_open () */
956 if (!font_info)
957 return;
958
959 for (i =0; i<0x100; i++)
960 {
961 xfree (font_info->glyphs[i]);
962 xfree (font_info->metrics[i]);
963 }
964 [font_info->nsfont release];
965 #ifdef NS_IMPL_COCOA
966 CGFontRelease (font_info->cgfont);
967 #endif
968 xfree (font_info->name);
969 xfree (font_info);
970 }
971
972
973 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
974 return 1. If not, return 0. If a font must be opened to check
975 it, return -1. */
976 static int
977 nsfont_has_char (Lisp_Object entity, int c)
978 {
979 return -1;
980 }
981
982
983 /* Return a glyph code of FONT for character C (Unicode code point).
984 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
985 static unsigned int
986 nsfont_encode_char (struct font *font, int c)
987 {
988 struct nsfont_info *font_info = (struct nsfont_info *)font;
989 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
990 unsigned short g;
991
992 if (c > 0xFFFF)
993 return FONT_INVALID_CODE;
994
995 /* did we already cache this block? */
996 if (!font_info->glyphs[high])
997 ns_uni_to_glyphs (font_info, high);
998
999 g = font_info->glyphs[high][low];
1000 return g == 0xFFFF ? FONT_INVALID_CODE : g;
1001 }
1002
1003
1004 /* Perform the size computation of glyphs of FONT and fill in members
1005 of METRICS. The glyphs are specified by their glyph codes in
1006 CODE (length NGLYPHS). */
1007 static int
1008 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
1009 struct font_metrics *metrics)
1010 {
1011 struct nsfont_info *font_info = (struct nsfont_info *)font;
1012 struct font_metrics *pcm;
1013 unsigned char high, low;
1014 int totalWidth = 0;
1015 int i;
1016
1017 memset (metrics, 0, sizeof (struct font_metrics));
1018
1019 for (i =0; i<nglyphs; i++)
1020 {
1021 /* get metrics for this glyph, filling cache if need be */
1022 /* TODO: get metrics for whole string from an NSLayoutManager
1023 (if not too slow) */
1024 high = (code[i] & 0xFF00) >> 8;
1025 low = code[i] & 0x00FF;
1026 if (!font_info->metrics[high])
1027 ns_glyph_metrics (font_info, high);
1028 pcm = &(font_info->metrics[high][low]);
1029
1030 if (metrics->lbearing > totalWidth + pcm->lbearing)
1031 metrics->lbearing = totalWidth + pcm->lbearing;
1032 if (metrics->rbearing < totalWidth + pcm->rbearing)
1033 metrics->rbearing = totalWidth + pcm->rbearing;
1034 if (metrics->ascent < pcm->ascent)
1035 metrics->ascent = pcm->ascent;
1036 if (metrics->descent < pcm->descent)
1037 metrics->descent = pcm->descent;
1038
1039 totalWidth += pcm->width;
1040 }
1041
1042 metrics->width = totalWidth;
1043
1044 return totalWidth; /* not specified in doc, but xfont.c does it */
1045 }
1046
1047
1048 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1049 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1050 fill the background in advance. It is assured that WITH_BACKGROUND
1051 is false when (FROM > 0 || TO < S->nchars). */
1052 static int
1053 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1054 bool with_background)
1055 /* NOTE: focus and clip must be set
1056 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1057 {
1058 static char cbuf[1024];
1059 char *c = cbuf;
1060 #ifdef NS_IMPL_GNUSTEP
1061 static float advances[1024];
1062 float *adv = advances;
1063 #else
1064 static CGSize advances[1024];
1065 CGSize *adv = advances;
1066 #endif
1067 struct face *face;
1068 NSRect r;
1069 struct nsfont_info *font = ns_tmp_font;
1070 NSColor *col, *bgCol;
1071 unsigned short *t = s->char2b;
1072 int i, len;
1073 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1074 int end = isComposite ? s->cmp_to : s->nchars;
1075
1076 /* Select face based on input flags */
1077 switch (ns_tmp_flags)
1078 {
1079 case NS_DUMPGLYPH_CURSOR:
1080 face = s->face;
1081 break;
1082 case NS_DUMPGLYPH_MOUSEFACE:
1083 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1084 if (!face)
1085 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1086 break;
1087 default:
1088 face = s->face;
1089 }
1090
1091 r.origin.x = s->x;
1092 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1093 r.origin.x += abs (s->face->box_line_width);
1094
1095 r.origin.y = s->y;
1096 r.size.height = FONT_HEIGHT (font);
1097
1098 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1099 NS to render the string, it will come out differently from the individual
1100 character widths added up because of layout processing. */
1101 {
1102 int cwidth, twidth = 0;
1103 int hi, lo;
1104 /* FIXME: composition: no vertical displacement is considered. */
1105 t += s->cmp_from; /* advance into composition */
1106 for (i = s->cmp_from; i < end; i++, t++)
1107 {
1108 hi = (*t & 0xFF00) >> 8;
1109 lo = *t & 0x00FF;
1110 if (isComposite)
1111 {
1112 if (!s->first_glyph->u.cmp.automatic)
1113 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1114 else
1115 {
1116 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1117 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1118 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1119 cwidth = LGLYPH_WIDTH (glyph);
1120 else
1121 {
1122 cwidth = LGLYPH_WADJUST (glyph);
1123 #ifdef NS_IMPL_GNUSTEP
1124 *(adv-1) += LGLYPH_XOFF (glyph);
1125 #else
1126 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1127 #endif
1128 }
1129 }
1130 }
1131 else
1132 {
1133 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1134 ns_glyph_metrics (font, hi);
1135 cwidth = font->metrics[hi][lo].width;
1136 }
1137 twidth += cwidth;
1138 #ifdef NS_IMPL_GNUSTEP
1139 *adv++ = cwidth;
1140 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1141 #else
1142 (*adv++).width = cwidth;
1143 #endif
1144 }
1145 len = adv - advances;
1146 r.size.width = twidth;
1147 *c = 0;
1148 }
1149
1150 /* fill background if requested */
1151 if (with_background && !isComposite)
1152 {
1153 NSRect br = r;
1154 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1155 int mbox_line_width = max (s->face->box_line_width, 0);
1156
1157 if (s->row->full_width_p)
1158 {
1159 if (br.origin.x <= fibw + 1 + mbox_line_width)
1160 {
1161 br.size.width += br.origin.x - mbox_line_width;
1162 br.origin.x = mbox_line_width;
1163 }
1164 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1165 <= fibw+1)
1166 br.size.width += fibw;
1167 }
1168 if (s->face->box == FACE_NO_BOX)
1169 {
1170 /* expand unboxed top row over internal border */
1171 if (br.origin.y <= fibw + 1 + mbox_line_width)
1172 {
1173 br.size.height += br.origin.y;
1174 br.origin.y = 0;
1175 }
1176 }
1177 else
1178 {
1179 int correction = abs (s->face->box_line_width)+1;
1180 br.origin.y += correction;
1181 br.size.height -= 2*correction;
1182 br.origin.x += correction;
1183 br.size.width -= 2*correction;
1184 }
1185
1186 if (!s->face->stipple)
1187 [(NS_FACE_BACKGROUND (face) != 0
1188 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1189 : FRAME_BACKGROUND_COLOR (s->f)) set];
1190 else
1191 {
1192 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1193 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1194 }
1195 NSRectFill (br);
1196 }
1197
1198
1199 /* set up for character rendering */
1200 r.origin.y = s->ybase;
1201
1202 col = (NS_FACE_FOREGROUND (face) != 0
1203 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1204 : FRAME_FOREGROUND_COLOR (s->f));
1205 /* FIXME: find another way to pass this */
1206 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
1207 : (NS_FACE_BACKGROUND (face) != 0
1208 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1209 : FRAME_BACKGROUND_COLOR (s->f)));
1210
1211 /* render under GNUstep using DPS */
1212 #ifdef NS_IMPL_GNUSTEP
1213 {
1214 NSGraphicsContext *context = GSCurrentContext ();
1215
1216 DPSgsave (context);
1217 [font->nsfont set];
1218
1219 /* do erase if "foreground" mode */
1220 if (bgCol != nil)
1221 {
1222 [bgCol set];
1223 DPSmoveto (context, r.origin.x, r.origin.y);
1224 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1225 DPSxshow (context, cbuf, advances, len);
1226 DPSstroke (context);
1227 [col set];
1228 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1229 }
1230
1231 [col set];
1232
1233 /* draw with DPSxshow () */
1234 DPSmoveto (context, r.origin.x, r.origin.y);
1235 DPSxshow (context, cbuf, advances, len);
1236 DPSstroke (context);
1237
1238 DPSgrestore (context);
1239 }
1240
1241 #else /* NS_IMPL_COCOA */
1242 {
1243 CGContextRef gcontext =
1244 [[NSGraphicsContext currentContext] graphicsPort];
1245 static CGAffineTransform fliptf;
1246 static BOOL firstTime = YES;
1247
1248 if (firstTime)
1249 {
1250 firstTime = NO;
1251 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1252 }
1253
1254 CGContextSaveGState (gcontext);
1255
1256 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1257
1258 CGContextSetFont (gcontext, font->cgfont);
1259 CGContextSetFontSize (gcontext, font->size);
1260 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1261 CGContextSetShouldAntialias (gcontext, 0);
1262 else
1263 CGContextSetShouldAntialias (gcontext, 1);
1264
1265 CGContextSetTextMatrix (gcontext, fliptf);
1266
1267 if (bgCol != nil)
1268 {
1269 /* foreground drawing; erase first to avoid overstrike */
1270 [bgCol set];
1271 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1272 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1273 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1274 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1275 }
1276
1277 [col set];
1278
1279 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1280 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1281 advances, len);
1282
1283 if (face->overstrike)
1284 {
1285 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1286 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1287 advances, len);
1288 }
1289
1290 CGContextRestoreGState (gcontext);
1291 }
1292 #endif /* NS_IMPL_COCOA */
1293
1294 /* Draw underline, overline, strike-through. */
1295 ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1296
1297 return to-from;
1298 }
1299
1300
1301
1302 /* ==========================================================================
1303
1304 Font glyph and metrics caching functions
1305
1306 ========================================================================== */
1307
1308 /* Find and cache corresponding glyph codes for unicode values in given
1309 hi-byte block of 256. */
1310 static void
1311 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1312 {
1313 #ifdef NS_IMPL_COCOA
1314 static EmacsGlyphStorage *glyphStorage;
1315 static char firstTime = 1;
1316 #endif
1317 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1318 unsigned int i, g, idx;
1319 unsigned short *glyphs;
1320
1321 if (NSFONT_TRACE)
1322 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1323 font_info, block);
1324
1325 block_input ();
1326
1327 #ifdef NS_IMPL_COCOA
1328 if (firstTime)
1329 {
1330 firstTime = 0;
1331 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1332 }
1333 #endif
1334
1335 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1336 if (!unichars || !(font_info->glyphs[block]))
1337 emacs_abort ();
1338
1339 /* create a string containing all Unicode characters in this block */
1340 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1341 if (idx < 0xD800 || idx > 0xDFFF)
1342 unichars[i] = idx;
1343 else
1344 unichars[i] = 0xFEFF;
1345 unichars[0x100] = 0;
1346
1347 {
1348 #ifdef NS_IMPL_COCOA
1349 NSString *allChars = [[NSString alloc]
1350 initWithCharactersNoCopy: unichars
1351 length: 0x100
1352 freeWhenDone: NO];
1353 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1354 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1355 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1356 NSUInteger gInd = 0, cInd = 0;
1357
1358 [glyphStorage setString: allChars font: font_info->nsfont];
1359 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1360 desiredNumberOfCharacters: glyphStorage->maxChar
1361 glyphIndex: &gInd characterIndex: &cInd];
1362 #endif
1363 glyphs = font_info->glyphs[block];
1364 for (i = 0; i < 0x100; i++, glyphs++)
1365 {
1366 #ifdef NS_IMPL_GNUSTEP
1367 g = unichars[i];
1368 #else
1369 g = glyphStorage->cglyphs[i];
1370 /* TODO: is this a good check? maybe need to use coveredChars.. */
1371 if (g > numGlyphs)
1372 g = 0xFFFF; /* hopefully unused... */
1373 #endif
1374 *glyphs = g;
1375 }
1376
1377 #ifdef NS_IMPL_COCOA
1378 [allChars release];
1379 #endif
1380 }
1381
1382 unblock_input ();
1383 xfree (unichars);
1384 }
1385
1386
1387 /* Determine and cache metrics for corresponding glyph codes in given
1388 hi-byte block of 256. */
1389 static void
1390 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1391 {
1392 unsigned int i, g;
1393 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1394 NSFont *sfont;
1395 struct font_metrics *metrics;
1396
1397 if (NSFONT_TRACE)
1398 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1399 font_info, block);
1400
1401 #ifdef NS_IMPL_GNUSTEP
1402 /* not implemented yet (as of startup 0.18), so punt */
1403 if (numGlyphs == 0)
1404 numGlyphs = 0x10000;
1405 #endif
1406
1407 block_input ();
1408 sfont = [font_info->nsfont screenFont];
1409
1410 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1411 if (!(font_info->metrics[block]))
1412 emacs_abort ();
1413
1414 metrics = font_info->metrics[block];
1415 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1416 {
1417 float w, lb, rb;
1418 NSRect r = [sfont boundingRectForGlyph: g];
1419
1420 w = max ([sfont advancementForGlyph: g].width, 2.0);
1421 metrics->width = lrint (w);
1422
1423 lb = r.origin.x;
1424 rb = r.size.width - w;
1425 if (lb < 0)
1426 metrics->lbearing = round (lb);
1427 if (font_info->ital)
1428 rb += 0.22 * font_info->height;
1429 metrics->rbearing = lrint (w + rb);
1430
1431 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1432 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1433 metrics->ascent = r.size.height - metrics->descent;
1434 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1435 }
1436 unblock_input ();
1437 }
1438
1439
1440 #ifdef NS_IMPL_COCOA
1441 /* helper for font glyph setup */
1442 @implementation EmacsGlyphStorage
1443
1444 - init
1445 {
1446 return [self initWithCapacity: 1024];
1447 }
1448
1449 - initWithCapacity: (unsigned long) c
1450 {
1451 self = [super init];
1452 maxChar = 0;
1453 maxGlyph = 0;
1454 dict = [NSMutableDictionary new];
1455 cglyphs = xmalloc (c * sizeof (CGGlyph));
1456 return self;
1457 }
1458
1459 - (void) dealloc
1460 {
1461 if (attrStr != nil)
1462 [attrStr release];
1463 [dict release];
1464 xfree (cglyphs);
1465 [super dealloc];
1466 }
1467
1468 - (void) setString: (NSString *)str font: (NSFont *)font
1469 {
1470 [dict setObject: font forKey: NSFontAttributeName];
1471 if (attrStr != nil)
1472 [attrStr release];
1473 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1474 maxChar = [str length];
1475 maxGlyph = 0;
1476 }
1477
1478 /* NSGlyphStorage protocol */
1479 - (NSUInteger)layoutOptions
1480 {
1481 return 0;
1482 }
1483
1484 - (NSAttributedString *)attributedString
1485 {
1486 return attrStr;
1487 }
1488
1489 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1490 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1491 characterIndex: (NSUInteger)charIndex
1492 {
1493 len = glyphIndex+length;
1494 for (i =glyphIndex; i<len; i++)
1495 cglyphs[i] = glyphs[i-glyphIndex];
1496 if (len > maxGlyph)
1497 maxGlyph = len;
1498 }
1499
1500 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1501 forGlyphAtIndex: (NSUInteger)glyphIndex
1502 {
1503 return;
1504 }
1505
1506 @end
1507 #endif /* NS_IMPL_COCOA */
1508
1509
1510 /* Debugging */
1511 void
1512 ns_dump_glyphstring (struct glyph_string *s)
1513 {
1514 int i;
1515
1516 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1517 "overlap = %d, bg_filled = %d:",
1518 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1519 s->row->overlapping_p, s->background_filled_p);
1520 for (i =0; i<s->nchars; i++)
1521 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1522 fprintf (stderr, "\n");
1523 }
1524
1525
1526 void
1527 syms_of_nsfont (void)
1528 {
1529 nsfont_driver.type = Qns;
1530 register_font_driver (&nsfont_driver, NULL);
1531 DEFSYM (Qapple, "apple");
1532 DEFSYM (Qroman, "roman");
1533 DEFSYM (Qmedium, "medium");
1534 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1535 doc: /* Internal use: maps font registry to Unicode script. */);
1536
1537 ascii_printable = NULL;
1538
1539 Vfonts_in_cache = Qnil;
1540 staticpro (&Vfonts_in_cache);
1541 }