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