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