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