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