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