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