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