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