]> code.delx.au - gnu-emacs/blob - src/nsfont.m
(add_user_signal): Fix typo in extern.
[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 nsfont_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 nsfont_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 nsfont_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 nsfont_unescape_name (tmp);
100 /* TODO: this seems to be needed only for font names that are
101 hard-coded into emacs, like 'helvetica' for splash screen */
102 if (tmp)
103 tmp[0] = toupper (tmp[0]);
104 family = [NSString stringWithUTF8String: tmp];
105 free (tmp);
106 return family;
107 }
108 }
109
110
111 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
112 /* TODO (20080601): The font backend's strategy for handling font
113 styles continues to evolve. When/if this stabilizes, we
114 can change the code here to be more sophisticated and accurate.
115 For now, we rely on "normal/plain" style being numeric 100. */
116 #define STYLE_REF 100
117 static unsigned int
118 nsfont_spec_to_traits (Lisp_Object font_spec)
119 {
120 unsigned int traits = 0;
121 int n;
122
123 n = FONT_WEIGHT_NUMERIC (font_spec);
124 if (n != -1)
125 traits |= (n > STYLE_REF) ? NSBoldFontMask
126 : (n < STYLE_REF) ? NSUnboldFontMask : 0;
127
128 n = FONT_SLANT_NUMERIC (font_spec);
129 if (n != -1)
130 traits |= (n > STYLE_REF) ? NSItalicFontMask
131 : (n < STYLE_REF) ? NSUnitalicFontMask : 0;
132
133 n = FONT_WIDTH_NUMERIC (font_spec);
134 if (n > -1)
135 traits |= (n > STYLE_REF + 10) ? NSExpandedFontMask
136 : (n < STYLE_REF - 10) ? NSExpandedFontMask : 0;
137
138 /*fprintf (stderr, " returning traits = %u\n", traits); */
139 return traits;
140 }
141
142
143 /* Converts NSArray of PS name, non-family part, weight, and traits to a
144 font backend font-entity. */
145 static Lisp_Object
146 nsfont_fmember_to_entity (NSString *family, NSArray *famMember)
147 {
148 Lisp_Object font_entity = font_make_entity ();
149 unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue];
150 /* NSString *psName = [famMember objectAtIndex: 0]; */
151 NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy];
152 char *escapedFamily = strdup ([family UTF8String]);
153
154 nsfont_escape_name (escapedFamily);
155 [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0
156 range: NSMakeRange (0, [suffix length])];
157
158 ASET (font_entity, FONT_TYPE_INDEX, Qns);
159 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
160 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
161 ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String]));
162 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
163
164 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
165 traits & NSBoldFontMask ? Qbold : Qmedium);
166 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
167 traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */
168 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
169 traits & NSCondensedFontMask ? Qcondensed :
170 traits & NSExpandedFontMask ? Qexpanded : Qnormal);
171
172 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
173 ASET (font_entity, FONT_EXTRA_INDEX, Qnil);
174 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
175
176 if (NSFONT_TRACE)
177 {
178 fprintf (stderr, "created font_entity:\n ");
179 debug_print (font_entity);
180 }
181
182 [suffix release];
183 free (escapedFamily);
184 return font_entity;
185 }
186
187
188 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */
189 static int
190 nsfont_trait_distance (unsigned int traits1, unsigned int traits2)
191 {
192 int i, d = 0;
193 for (i = 0; i < sizeof (unsigned int) * 8; i++)
194 {
195 d += (traits1 & 0x1) ^ (traits2 & 0x1);
196 traits1 >>= 1;
197 traits2 >>= 1;
198 }
199 return d;
200 }
201
202
203 /* Default font entity based on Monaco. */
204 static Lisp_Object
205 nsfont_fallback_entity ()
206 {
207 NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
208 NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"",
209 [NSNumber numberWithUnsignedInt: 5],
210 [NSNumber numberWithUnsignedInt: 0], nil];
211 return nsfont_fmember_to_entity (family, famMemberSpec);
212 }
213
214
215 /* ==========================================================================
216
217 Font driver implementation
218
219 ========================================================================== */
220
221 static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
222 static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
223 static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
224 static Lisp_Object nsfont_list_family (Lisp_Object frame);
225 static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
226 int pixel_size);
227 static void nsfont_close (FRAME_PTR f, struct font *font);
228 static int nsfont_has_char (Lisp_Object entity, int c);
229 static unsigned int nsfont_encode_char (struct font *font, int c);
230 static int nsfont_text_extents (struct font *font, unsigned int *code,
231 int nglyphs, struct font_metrics *metrics);
232 static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
233 int with_background);
234
235 struct font_driver nsfont_driver =
236 {
237 0, /* Qns */
238 1, /* case sensitive */
239 nsfont_get_cache,
240 nsfont_list,
241 nsfont_match,
242 nsfont_list_family,
243 NULL, /*free_entity */
244 nsfont_open,
245 nsfont_close,
246 NULL, /* prepare_face */
247 NULL, /* done_face */
248 nsfont_has_char,
249 nsfont_encode_char,
250 nsfont_text_extents,
251 nsfont_draw,
252 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
253 anchor_point, otf_capability, otf_driver,
254 start_for_frame, end_for_frame, shape */
255 };
256
257
258 /* Return a cache of font-entities on FRAME. The cache must be a
259 cons whose cdr part is the actual cache area. */
260 static Lisp_Object
261 nsfont_get_cache (FRAME_PTR frame)
262 {
263 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
264 return (dpyinfo->name_list_element);
265 }
266
267
268 /* List fonts exactly matching with FONT_SPEC on FRAME. The value
269 is a **list** of font-entities. This is the sole API that
270 allocates font-entities. */
271 static Lisp_Object
272 nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
273 {
274 Lisp_Object list = Qnil;
275 Lisp_Object tem;
276 NSString *family;
277 NSArray *families;
278 NSEnumerator *famEnum;
279 NSFontManager *fontMgr;
280 unsigned int traits = nsfont_spec_to_traits (font_spec);
281
282 if (NSFONT_TRACE)
283 {
284 fprintf (stderr, "nsfont: list for fontspec:\n ");
285 debug_print (font_spec);
286 }
287
288 /* if has non-unicode registry, give up */
289 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
290 if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
291 return Qnil;
292
293 fontMgr = [NSFontManager sharedFontManager];
294
295 family = nsfont_get_family (font_spec);
296
297 if (family != nil)
298 families = [NSArray arrayWithObject: family];
299 else
300 families = [fontMgr availableFontFamilies];
301
302 for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; )
303 {
304 NSEnumerator *fm;
305 NSArray *fmember, *firstMember = nil;
306 unsigned int mtraits;
307 BOOL foundItal = NO || (traits & NSUnitalicFontMask);
308 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
309 #ifdef NS_IMPL_COCOA
310 /* LastResort is special: not a family but a font name only */
311 if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0)
312 {
313 famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects:
314 @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5],
315 [NSNumber numberWithUnsignedInt: 0], nil]];
316 }
317 #endif
318
319 /* fmember = [postscriptName style weight traits] */
320 fm = [famMembers objectEnumerator];
321 while (fmember = [fm nextObject])
322 {
323 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
324 if ((mtraits & traits) == traits)
325 {
326 list = Fcons (nsfont_fmember_to_entity (family, fmember), list);
327 if (mtraits & NSItalicFontMask)
328 foundItal = YES;
329 if (firstMember == nil)
330 firstMember = fmember;
331 }
332 }
333 if (foundItal == NO && firstMember != nil)
334 {
335 /* no italic member found; add a synthesized one */
336 NSMutableArray *smember = [firstMember mutableCopy];
337 [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ];
338 mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
339 mtraits |= NSItalicFontMask;
340 [smember replaceObjectAtIndex: 3
341 withObject: [NSNumber numberWithUnsignedInt: mtraits]];
342 /*NSLog (@"-- adding synthItal member: %@", smember); */
343 list = Fcons (nsfont_fmember_to_entity (family, smember), list);
344 [smember release];
345 }
346 }
347
348 if (NSFONT_TRACE)
349 fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list)));
350
351 return list;
352 }
353
354
355 /* Return a font entity most closely maching with FONT_SPEC on
356 FRAME. The closeness is determined by the font backend, thus
357 `face-font-selection-order' is ignored here. */
358 static Lisp_Object
359 nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
360 {
361 long traits = nsfont_spec_to_traits (font_spec);
362 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
363 NSString *family;
364 Lisp_Object tem;
365
366 if (NSFONT_TRACE)
367 {
368 fprintf (stderr, "nsfont: match for fontspec:\n ");
369 debug_print (font_spec);
370 }
371
372 /* if has non-unicode registry, just return fallback */
373 #if 0
374 tem = AREF (font_spec, FONT_ADSTYLE_INDEX);
375 if (!NILP (tem))
376 fprintf (stderr, "adstyle: '%s'\n", SDATA (tem));
377 #endif
378 tem = AREF (font_spec, FONT_REGISTRY_INDEX);
379 if (!NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp))
380 return nsfont_fallback_entity ();
381
382 family = nsfont_get_family (font_spec);
383
384 if (family != nil)
385 {
386 /* try to find close font in family */
387 NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family];
388 NSEnumerator *fm = [famMembers objectEnumerator];
389 NSArray *fmember;
390 int minDist = sizeof (unsigned int) * 8 + 1;
391 int bestMatchIdx = -1;
392 int i;
393
394 for (i =0; fmember = [fm nextObject]; i++)
395 {
396 unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue];
397 int dist = nsfont_trait_distance ((mtraits & traits), traits);
398 if (dist < minDist)
399 {
400 bestMatchIdx = i;
401 minDist = dist;
402 }
403 }
404 if (bestMatchIdx != -1)
405 return nsfont_fmember_to_entity
406 (family, [famMembers objectAtIndex: bestMatchIdx]);
407 }
408
409 /* no family that had members was given; find any font matching traits */
410 {
411 NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits];
412 if (fontNames && [fontNames count] > 0)
413 {
414 NSString *fontName = [fontNames objectAtIndex: 0];
415 /* XXX: is there a more efficient way to get family name? */
416 NSFont *font = [NSFont fontWithName: fontName size: 0];
417 if (font != nil)
418 {
419 /* now need to get suffix part of name.. */
420 NSString *family = [font familyName];
421 NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family]
422 objectEnumerator];
423 NSArray *fmember;
424 while (fmember = [fm nextObject])
425 {
426 unsigned int mtraits =
427 [[fmember objectAtIndex: 3] unsignedIntValue];
428 if (mtraits & traits == traits)
429 return nsfont_fmember_to_entity (family, fmember);
430 }
431 }
432 }
433 }
434
435 /* if we get here, return the fallback */
436 if (NSFONT_TRACE)
437 fprintf (stderr, " *** returning fallback\n");
438
439 return nsfont_fallback_entity ();
440 }
441
442
443 /* List available families. The value is a list of family names
444 (symbols). */
445 static Lisp_Object
446 nsfont_list_family (Lisp_Object frame)
447 {
448 Lisp_Object list = Qnil;
449 NSEnumerator *families =
450 [[[NSFontManager sharedFontManager] availableFontFamilies]
451 objectEnumerator];
452 NSString *family;
453 while (family = [families nextObject])
454 list = Fcons (intern ([family UTF8String]), list);
455 /* FIXME: escape the name? */
456
457 if (NSFONT_TRACE)
458 fprintf (stderr, "nsfont: list families returning %d entries\n",
459 XINT (Flength (list)));
460
461 return list;
462 }
463
464
465 /* utility: get width of a char c in screen font sfont */
466 static float
467 nsfont_char_width (NSFont *sfont, int c)
468 {
469 float w;
470 NSString *cstr = [NSString stringWithFormat: @"%c", c];
471 #ifdef NS_IMPL_COCOA
472 NSGlyph glyph = [sfont glyphWithName: cstr];
473 if (glyph)
474 {
475 float w = [sfont advancementForGlyph: glyph].width;
476 if (w >= 1.5)
477 return w;
478 }
479 #endif
480 w = [sfont widthOfString: cstr];
481 return max (w, 2.0);
482 }
483
484
485 /* Open a font specified by FONT_ENTITY on frame F. If the font is
486 scalable, open it with PIXEL_SIZE. */
487 static Lisp_Object
488 nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
489 {
490 BOOL synthItal;
491 struct nsfont_info *font_info;
492 struct font *font;
493 unsigned int traits = nsfont_spec_to_traits (font_entity);
494 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
495 NSString *family;
496 NSFont *nsfont, *sfont;
497 Lisp_Object tem;
498 NSRect brect;
499 Lisp_Object font_object;
500 int i;
501 int fixLeopardBug;
502 static NSMutableDictionary *fontCache = nil;
503 NSNumber *cached;
504
505 /* 2008/03/08: The same font may end up being requested for different
506 entities, due to small differences in numeric values or other issues,
507 or for different copies of the same entity. Therefore we cache to
508 avoid creating multiple struct font objects (with metrics cache, etc.)
509 for the same NSFont object.
510 2008/06/01: This is still an issue after font backend refactoring. */
511 if (fontCache == nil)
512 fontCache = [[NSMutableDictionary alloc] init];
513
514 if (NSFONT_TRACE)
515 {
516 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
517 debug_print (font_entity);
518 }
519
520 if (pixel_size <= 0)
521 {
522 /* try to get it out of frame params */
523 Lisp_Object tem = get_frame_param (f, Qfontsize);
524 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
525 }
526
527 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
528 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
529 9);
530 family = nsfont_get_family (font_entity);
531 if (NSFONT_TRACE)
532 {
533 fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\titalic = %d\n",
534 [family UTF8String], traits, traits & NSBoldFontMask,
535 traits & NSItalicFontMask);
536 }
537
538 /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
539 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
540 nsfont = [fontMgr fontWithFamily: family
541 traits: traits weight: fixLeopardBug
542 size: pixel_size];
543 /* if didn't find, try synthetic italic */
544 if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
545 {
546 nsfont = [fontMgr fontWithFamily: family
547 traits: traits & ~NSItalicFontMask
548 weight: fixLeopardBug size: pixel_size];
549 }
550 #ifdef NS_IMPL_COCOA
551 /* LastResort not really a family */
552 if (nsfont == nil && [@"LastResort" isEqualToString: family])
553 {
554 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
555 }
556 #endif
557
558 if (nsfont == nil)
559 {
560 message_with_string ("*** Warning: font in family '%s' not found",
561 build_string ([family UTF8String]), 1);
562 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
563 if (!nsfont)
564 {
565 fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
566 return Qnil;
567 }
568 }
569
570 if (NSFONT_TRACE)
571 NSLog (@"%@\n", nsfont);
572
573 /* Check the cache */
574 cached = [fontCache objectForKey: nsfont];
575 if (cached != nil && !synthItal)
576 {
577 if (NSFONT_TRACE)
578 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
579 // FIXME: Cast from (unsigned long) to Lisp_Object.
580 XHASH (font_object) = [cached unsignedLongValue];
581 return font_object;
582 }
583 else
584 {
585 font_object = font_make_object (VECSIZE (struct nsfont_info),
586 font_entity, pixel_size);
587 if (!synthItal)
588 [fontCache
589 setObject: [NSNumber numberWithUnsignedLong:
590 (unsigned long) XHASH (font_object)]
591 forKey: nsfont];
592 }
593
594 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
595 font = (struct font *)font_info;
596 if (!font)
597 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
598
599 font_info->glyphs = (unsigned short **)
600 xmalloc (0x100 * sizeof (unsigned short *));
601 font_info->metrics = (struct font_metrics **)
602 xmalloc (0x100 * sizeof (struct font_metrics *));
603 if (!font_info->glyphs || !font_info->metrics)
604 return Qnil;
605 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
606 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
607
608 BLOCK_INPUT;
609
610 /* for metrics */
611 sfont = [nsfont screenFont];
612 if (sfont == nil)
613 sfont = nsfont;
614
615 /* non-metric backend font struct fields */
616 font = (struct font *) font_info;
617 font->pixel_size = [sfont pointSize];
618 font->driver = &nsfont_driver;
619 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
620 font->encoding_charset = -1;
621 font->repertory_charset = -1;
622 font->default_ascent = 0;
623 font->vertical_centering = 0;
624 font->baseline_offset = 0;
625 font->relative_compose = 0;
626 font->font_encoder = NULL;
627
628 /* TODO: does anything care about this? */
629 font->props[FONT_FORMAT_INDEX] = Qns;
630 font->props[FONT_FILE_INDEX] = Qnil;
631
632 {
633 double expand, hshrink;
634 float full_height, min_height, hd;
635 const char *fontName = [[nsfont fontName] UTF8String];
636 int len = strlen (fontName);
637
638 #ifdef NS_IMPL_GNUSTEP
639 font_info->nsfont = sfont;
640 #else
641 font_info->nsfont = nsfont;
642 #endif
643 [font_info->nsfont retain];
644
645 /* set up ns_font (defined in nsgui.h) */
646 font_info->name = (char *)xmalloc (strlen (fontName)+1);
647 bcopy (fontName, font_info->name, strlen (fontName)+1);
648 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
649 font_info->ital =
650 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
651
652 /* Metrics etc.; some fonts return an unusually large max advance, so we
653 only use it for fonts that have wide characters. */
654 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
655 [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
656
657 brect = [sfont boundingRectForFont];
658 full_height = brect.size.height;
659 min_height = [sfont ascender] - [sfont descender];
660 hd = full_height - min_height;
661
662 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
663 expand = 0.0;
664 hshrink = 1.0;
665
666 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
667 font_info->underwidth = [sfont underlineThickness];
668 font_info->size = font->pixel_size;
669 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
670
671 /* max bounds */
672 font_info->max_bounds.ascent =
673 lrint (hshrink * [sfont ascender] + expand * hd/2);
674 font_info->max_bounds.descent =
675 -lrint (hshrink* [sfont descender] - expand*hd/2);
676 font_info->height =
677 font_info->max_bounds.ascent + font_info->max_bounds.descent;
678 font_info->max_bounds.width = lrint (font_info->width);
679 font_info->max_bounds.lbearing = lrint (brect.origin.x);
680 font_info->max_bounds.rbearing =
681 lrint (brect.size.width - font_info->width);
682
683 #ifdef NS_IMPL_COCOA
684 /* set up synthItal and the CG font */
685 font_info->synthItal = synthItal;
686 {
687 ATSFontRef atsFont = ATSFontFindFromPostScriptName
688 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
689
690 if (atsFont == kATSFontRefUnspecified)
691 {
692 /* see if we can get it by dropping italic (then synthesizing) */
693 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
694 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
695 fontName], kATSOptionFlagsDefault);
696 if (atsFont != kATSFontRefUnspecified)
697 font_info->synthItal = YES;
698 else
699 {
700 /* last resort fallback */
701 atsFont = ATSFontFindFromPostScriptName
702 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
703 }
704 }
705 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
706 }
707 #endif
708
709 /* set up metrics portion of font struct */
710 font->ascent = [sfont ascender];
711 font->descent = -[sfont descender];
712 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
713 font->space_width = lrint (nsfont_char_width (sfont, ' '));
714 font->average_width = lrint (font_info->width);
715 font->max_width = lrint (font_info->max_bounds.width);
716 font->height = lrint (font_info->height);
717 font->underline_position = lrint (font_info->underpos);
718 font->underline_thickness = lrint (font_info->underwidth);
719
720 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
721 font->props[FONT_FULLNAME_INDEX] =
722 make_unibyte_string (font_info->name, strlen (font_info->name));
723 }
724 UNBLOCK_INPUT;
725
726 return font_object;
727 }
728
729
730 /* Close FONT on frame F. */
731 static void
732 nsfont_close (FRAME_PTR f, struct font *font)
733 {
734 struct nsfont_info *font_info = (struct nsfont_info *)font;
735 int i;
736
737 /* FIXME: this occurs apparently due to same failure to detect same font
738 that causes need for cache in nsfont_open ()
739 (came after unicode-2 -> trunk) */
740 if (!font_info)
741 return;
742
743 for (i =0; i<0x100; i++)
744 {
745 if (font_info->glyphs[i])
746 xfree (font_info->glyphs[i]);
747 if (font_info->metrics[i])
748 xfree (font_info->metrics[i]);
749 }
750 [font_info->nsfont release];
751 #ifdef NS_IMPL_COCOA
752 CGFontRelease (font_info->cgfont);
753 #endif
754 xfree (font_info->name);
755 xfree (font_info);
756 }
757
758
759 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
760 return 1. If not, return 0. If a font must be opened to check
761 it, return -1. */
762 static int
763 nsfont_has_char (Lisp_Object entity, int c)
764 {
765 return -1;
766 }
767
768
769 /* Return a glyph code of FONT for character C (Unicode code point).
770 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
771 static unsigned int
772 nsfont_encode_char (struct font *font, int c)
773 {
774 struct nsfont_info *font_info = (struct nsfont_info *)font;
775 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
776 unsigned short g;
777
778 if (c > 0xFFFF)
779 return FONT_INVALID_CODE;
780
781 /* did we already cache this block? */
782 if (!font_info->glyphs[high])
783 ns_uni_to_glyphs (font_info, high);
784
785 g = font_info->glyphs[high][low];
786 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
787 return g == 0xFFFF ? FONT_INVALID_CODE : g;
788 }
789
790
791 /* Perform the size computation of glyphs of FONT and fill in members
792 of METRICS. The glyphs are specified by their glyph codes in
793 CODE (length NGLYPHS). */
794 static int
795 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
796 struct font_metrics *metrics)
797 {
798 struct nsfont_info *font_info = (struct nsfont_info *)font;
799 struct font_metrics *pcm;
800 unsigned char high, low;
801 int totalWidth = 0;
802 int i;
803
804 bzero (metrics, sizeof (struct font_metrics));
805
806 for (i =0; i<nglyphs; i++)
807 {
808 /* get metrics for this glyph, filling cache if need be */
809 /* TODO: get metrics for whole string from an NSLayoutManager
810 (if not too slow) */
811 high = (code[i] & 0xFF00) >> 8;
812 low = code[i] & 0x00FF;
813 if (!font_info->metrics[high])
814 ns_glyph_metrics (font_info, high);
815 pcm = &(font_info->metrics[high][low]);
816
817 if (metrics->lbearing > totalWidth + pcm->lbearing)
818 metrics->lbearing = totalWidth + pcm->lbearing;
819 if (metrics->rbearing < totalWidth + pcm->rbearing)
820 metrics->rbearing = totalWidth + pcm->rbearing;
821 if (metrics->ascent < pcm->ascent)
822 metrics->ascent = pcm->ascent;
823 if (metrics->descent < pcm->descent)
824 metrics->descent = pcm->descent;
825
826 totalWidth += pcm->width;
827 }
828
829 metrics->width = totalWidth;
830
831 return totalWidth; /* not specified in doc, but xfont.c does it */
832 }
833
834
835 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
836 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
837 is nonzero, fill the background in advance. It is assured that
838 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
839 static int
840 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
841 int with_background)
842 /* NOTE: focus and clip must be set
843 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
844 {
845 static char cbuf[1024];
846 char *c = cbuf;
847 #ifdef NS_IMPL_GNUSTEP
848 static float advances[1024];
849 float *adv = advances;
850 #else
851 static CGSize advances[1024];
852 CGSize *adv = advances;
853 #endif
854 struct face *face;
855 NSRect r;
856 struct nsfont_info *font = ns_tmp_font;
857 NSColor *col, *bgCol;
858 unsigned short *t = s->char2b;
859 int i, len;
860
861 /* Select face based on input flags */
862 switch (ns_tmp_flags)
863 {
864 case NS_DUMPGLYPH_CURSOR:
865 face = s->face;
866 break;
867 case NS_DUMPGLYPH_MOUSEFACE:
868 face = FACE_FROM_ID (s->f,
869 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
870 if (!face)
871 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
872 break;
873 default:
874 face = s->face;
875 }
876
877 r.origin.x = s->x;
878 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
879 r.origin.x += abs (s->face->box_line_width);
880
881 r.origin.y = s->y;
882 r.size.height = FONT_HEIGHT (font);
883
884 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
885 NS to render the string, it will come out differently from the individual
886 character widths added up because of layout processing. */
887 {
888 XCharStruct *cs;
889 int cwidth, twidth = 0;
890 int hi, lo;
891 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
892 /* FIXME: composition: no vertical displacement is considered. */
893 t += s->cmp_from; /* advance into composition */
894 for (i = s->cmp_from; i < s->nchars; i++, t++)
895 {
896 hi = (*t & 0xFF00) >> 8;
897 lo = *t & 0x00FF;
898 if (isComposite)
899 {
900 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
901 }
902 else
903 {
904 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
905 ns_glyph_metrics (font, hi);
906 cwidth = font->metrics[hi][lo].width;
907 }
908 twidth += cwidth;
909 #ifdef NS_IMPL_GNUSTEP
910 *adv++ = cwidth;
911 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
912 #else
913 (*adv++).width = cwidth;
914 #endif
915 }
916 len = adv - advances;
917 r.size.width = twidth;
918 *c = 0;
919 }
920
921 /* fill background if requested */
922 if (with_background)
923 {
924 NSRect br = r;
925 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
926 int mbox_line_width = max (s->face->box_line_width, 0);
927
928 if (s->row->full_width_p)
929 {
930 if (br.origin.x <= fibw + 1 + mbox_line_width)
931 {
932 br.size.width += br.origin.x - mbox_line_width;
933 br.origin.x = mbox_line_width;
934 }
935 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
936 <= fibw+1)
937 br.size.width += fibw;
938 }
939 if (s->face->box == FACE_NO_BOX)
940 {
941 /* expand unboxed top row over internal border */
942 if (br.origin.y <= fibw + 1 + mbox_line_width)
943 {
944 br.size.height += br.origin.y;
945 br.origin.y = 0;
946 }
947 }
948 else
949 {
950 int correction = abs (s->face->box_line_width)+1;
951 br.origin.y += correction;
952 br.size.height -= 2*correction;
953 br.origin.x += correction;
954 br.size.width -= 2*correction;
955 }
956
957 if (!s->face->stipple)
958 [(NS_FACE_BACKGROUND (face) != 0
959 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
960 : FRAME_BACKGROUND_COLOR (s->f)) set];
961 else
962 {
963 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
964 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
965 }
966 NSRectFill (br);
967 }
968
969
970 /* set up for character rendering */
971 r.origin.y += font->voffset + (s->height - font->height)/2;
972
973 col = (NS_FACE_FOREGROUND (face) != 0
974 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
975 : FRAME_FOREGROUND_COLOR (s->f));
976 /* FIXME: find another way to pass this */
977 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
978 : (NS_FACE_BACKGROUND (face) != 0
979 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
980 : FRAME_BACKGROUND_COLOR (s->f)));
981
982 /* render under GNUstep using DPS */
983 #ifdef NS_IMPL_GNUSTEP
984 {
985 NSGraphicsContext *context = GSCurrentContext ();
986
987 DPSgsave (context);
988 [font->nsfont set];
989
990 /* do erase if "foreground" mode */
991 if (bgCol != nil)
992 {
993 [bgCol set];
994 DPSmoveto (context, r.origin.x, r.origin.y);
995 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
996 DPSxshow (context, cbuf, advances, len);
997 DPSstroke (context);
998 [col set];
999 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1000 }
1001
1002 /* do underline */
1003 if (face->underline_p)
1004 {
1005 if (face->underline_color != 0)
1006 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1007 else
1008 [col set];
1009 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1010 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1011 if (face->underline_color != 0)
1012 [col set];
1013 }
1014 else
1015 [col set];
1016
1017 /* draw with DPSxshow () */
1018 DPSmoveto (context, r.origin.x, r.origin.y);
1019 DPSxshow (context, cbuf, advances, len);
1020 DPSstroke (context);
1021
1022 DPSgrestore (context);
1023 return to-from;
1024 }
1025
1026 #else /* NS_IMPL_COCOA */
1027 {
1028 CGContextRef gcontext =
1029 [[NSGraphicsContext currentContext] graphicsPort];
1030 static CGAffineTransform fliptf;
1031 static BOOL firstTime = YES;
1032
1033 if (firstTime)
1034 {
1035 firstTime = NO;
1036 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1037 }
1038
1039 CGContextSaveGState (gcontext);
1040
1041 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1042
1043 CGContextSetFont (gcontext, font->cgfont);
1044 CGContextSetFontSize (gcontext, font->size);
1045 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1046 CGContextSetShouldAntialias (gcontext, 0);
1047 else
1048 CGContextSetShouldAntialias (gcontext, 1);
1049 if (EQ (ns_use_qd_smoothing, Qt))
1050 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1051
1052 CGContextSetTextMatrix (gcontext, fliptf);
1053
1054 if (bgCol != nil)
1055 {
1056 /* foreground drawing; erase first to avoid overstrike */
1057 [bgCol set];
1058 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1059 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1060 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1061 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1062 }
1063
1064 if (face->underline_p)
1065 {
1066 if (face->underline_color != 0)
1067 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1068 else
1069 [col set];
1070 CGContextBeginPath (gcontext);
1071 CGContextMoveToPoint (gcontext,
1072 r.origin.x, r.origin.y + font->underpos);
1073 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1074 r.origin.y + font->underpos);
1075 CGContextStrokePath (gcontext);
1076 if (face->underline_color != 0)
1077 [col set];
1078 }
1079 else
1080 [col set];
1081
1082 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1083 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1084 advances, len);
1085
1086 if (face->overstrike)
1087 {
1088 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1089 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1090 advances, len);
1091 }
1092
1093 CGContextRestoreGState (gcontext);
1094 return;
1095 }
1096 #endif /* NS_IMPL_COCOA */
1097
1098 }
1099
1100
1101 /* Auto-creates a fontset built around the font in font_object,
1102 by creating an attributed string with characters from each
1103 script, then requesting the NS text system to fix attributes
1104 in range. */
1105 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1106 {
1107 Lisp_Object script, famAndReg;
1108 struct nsfont_info *font_info =
1109 (struct nsfont_info *)XFONT_OBJECT (font_object);
1110
1111 /* NS text system (and char buf) init */
1112 static NSTextStorage *store;
1113 static NSLayoutManager *layout;
1114 static NSRange range;
1115 static NSMutableDictionary *attribs;
1116 static Lisp_Object *scripts;
1117 static int nscripts;
1118 static int *scriptsNchars;
1119 static BOOL firstTime = YES;
1120 Lisp_Object regString = build_string ("iso10646-1");
1121 int i, j;
1122
1123 if (firstTime == YES)
1124 {
1125 nscripts = XINT (Flength (Vscript_representative_chars));
1126 scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1127 unsigned char *buf = malloc (4*nscripts*sizeof (char));
1128 Lisp_Object scriptsChars = Vscript_representative_chars;
1129 unsigned char *tpos = buf;
1130
1131 scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1132
1133 for (i =0; i<nscripts; i++)
1134 {
1135 Lisp_Object sChars = XCAR (scriptsChars);
1136 Lisp_Object chars = XCDR (sChars);
1137 unsigned int ch, c =0;
1138 scripts[i] = XCAR (sChars);
1139
1140 while (CONSP (chars))
1141 {
1142 ch = XUINT (XCAR (chars));
1143 chars = XCDR (chars);
1144 CHAR_STRING_ADVANCE (ch, tpos);
1145 c++;
1146 }
1147 scriptsNchars[i] = c;
1148
1149 scriptsChars = XCDR (scriptsChars);
1150 }
1151 *tpos = '\0';
1152
1153 store = [[NSTextStorage alloc] init];
1154 layout = [[NSLayoutManager alloc] init];
1155 [store addLayoutManager: layout];
1156 [layout release];
1157
1158 [store beginEditing];
1159 [[store mutableString] appendString:
1160 [NSString stringWithUTF8String: buf]];
1161 [store endEditing];
1162
1163 free (buf);
1164 range = NSMakeRange (0, [store length]);
1165
1166 attribs = [[NSMutableDictionary alloc] init];
1167 firstTime = NO;
1168 }
1169
1170 /* set the fonts */
1171 [store beginEditing];
1172 [store removeAttribute: NSFontAttributeName range: range];
1173 [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1174 [store addAttributes: attribs range: range];
1175 [store endEditing];
1176
1177 /* read them out */
1178 {
1179 NSMutableDictionary *map =
1180 [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1181 NSEnumerator *fonts;
1182 NSFont *cfont = nil, *tfont;
1183 NSNumber *n;
1184 int idx = 0;
1185 int max;
1186 for (i =0; i<nscripts; i++)
1187 {
1188 [map removeAllObjects];
1189 for (j =0; j<scriptsNchars[i]; j++)
1190 {
1191 cfont = [store attribute: NSFontAttributeName atIndex: idx++
1192 effectiveRange: NULL];
1193 n = [map objectForKey: cfont];
1194 if (n == nil)
1195 n = [NSNumber numberWithInt: 1];
1196 else
1197 n = [NSNumber numberWithInt: [n intValue] + 1];
1198 [map setObject: n forKey: cfont];
1199 }
1200
1201 /* majority rules */
1202 max = 0;
1203 fonts = [map keyEnumerator];
1204 while (tfont = [fonts nextObject])
1205 {
1206 n = [map objectForKey: tfont];
1207 if ([n intValue] > max)
1208 {
1209 cfont = tfont;
1210 max = [n intValue];
1211 }
1212 }
1213
1214 if (cfont != nil)
1215 {
1216 char *family = strdup([[cfont familyName] UTF8String]);
1217 Lisp_Object famAndReg;
1218
1219 nsfont_escape_name (family);
1220 famAndReg = Fcons (build_string (family), regString);
1221
1222 if (NSFONT_TRACE)
1223 fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1224 font_info->name, family,
1225 SDATA (SYMBOL_NAME (scripts[i])));
1226
1227 /* TODO: Some of the "scripts" in script-representative-chars are
1228 actually only "sub-scripts" which are not fully defined. For
1229 these, calling set_fontset_font generates an abort. Try to
1230 guess which ones these are and avoid it. */
1231 if (strstr (SDATA (SYMBOL_NAME (scripts[i])), "mathematical-")
1232 != SDATA (SYMBOL_NAME (scripts[i])))
1233 Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1234 free (family);
1235 }
1236 else
1237 {
1238 fprintf (stderr, "%s fontset: none found for script '%s'\n",
1239 font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1240 }
1241 } /* for i = script */
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 dump_glyphstring (struct glyph_string *s)
1466 {
1467 int i;
1468
1469 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1470 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1471 s->row->overlapping_p, s->background_filled_p);
1472 for (i =0; i<s->nchars; i++)
1473 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1474 fprintf (stderr, "\n");
1475 }
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