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