]> code.delx.au - gnu-emacs/blob - src/nsfont.m
(redraw_overlapping_rows): Fix detection of
[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 return (Lisp_Object)[cached unsignedLongValue];
580 }
581 else
582 {
583 font_object = font_make_object (VECSIZE (struct nsfont_info),
584 font_entity, pixel_size);
585 if (!synthItal)
586 [fontCache
587 setObject: [NSNumber numberWithUnsignedLong:
588 (unsigned long)font_object]
589 forKey: nsfont];
590 }
591
592 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
593 font = (struct font *)font_info;
594 if (!font)
595 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
596
597 font_info->glyphs = (unsigned short **)
598 xmalloc (0x100 * sizeof (unsigned short *));
599 font_info->metrics = (struct font_metrics **)
600 xmalloc (0x100 * sizeof (struct font_metrics *));
601 if (!font_info->glyphs || !font_info->metrics)
602 return Qnil;
603 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
604 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
605
606 BLOCK_INPUT;
607
608 /* for metrics */
609 sfont = [nsfont screenFont];
610 if (sfont == nil)
611 sfont = nsfont;
612
613 /* non-metric backend font struct fields */
614 font = (struct font *) font_info;
615 font->pixel_size = [sfont pointSize];
616 font->driver = &nsfont_driver;
617 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
618 font->encoding_charset = -1;
619 font->repertory_charset = -1;
620 font->default_ascent = 0;
621 font->vertical_centering = 0;
622 font->baseline_offset = 0;
623 font->relative_compose = 0;
624 font->font_encoder = NULL;
625
626 /* TODO: does anything care about this? */
627 font->props[FONT_FORMAT_INDEX] = Qns;
628 font->props[FONT_FILE_INDEX] = Qnil;
629
630 {
631 double expand, shrink, hshrink;
632 float full_height, min_height, hd;
633 const char *fontName = [[nsfont fontName] UTF8String];
634 int len = strlen (fontName);
635
636 #ifdef NS_IMPL_GNUSTEP
637 font_info->nsfont = sfont;
638 #else
639 font_info->nsfont = nsfont;
640 #endif
641 [font_info->nsfont retain];
642
643 /* set up ns_font (defined in nsgui.h) */
644 font_info->name = (char *)xmalloc (strlen (fontName)+1);
645 bcopy (fontName, font_info->name, strlen (fontName)+1);
646 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
647 font_info->ital =
648 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
649
650 /* Metrics etc.; some fonts return an unusually large max advance, so we
651 only use it for fonts that have wide characters. */
652 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
653 [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
654
655 brect = [sfont boundingRectForFont];
656 full_height = brect.size.height;
657 min_height = [sfont ascender] - [sfont descender];
658 hd = full_height - min_height;
659
660 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
661 expand = 0.0;
662 shrink = 1.0;
663 hshrink = 1.0;
664
665 /*
666 if (expand < 0.0)
667 {
668 shrink = 1 + expand;
669 hshrink = 1 + expand / 2.0;
670 expand = 0.0;
671 }
672 else
673 shrink = hshrink = 1.0;
674 */
675
676 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
677 font_info->underwidth = [sfont underlineThickness];
678 font_info->size = font->pixel_size;
679 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
680
681 /* max bounds */
682 font_info->max_bounds.ascent =
683 lrint (hshrink * [sfont ascender] + expand * hd/2);
684 font_info->max_bounds.descent =
685 -lrint (hshrink* [sfont descender] - expand*hd/2);
686 font_info->height =
687 font_info->max_bounds.ascent + font_info->max_bounds.descent;
688 font_info->max_bounds.width = lrint (font_info->width);
689 font_info->max_bounds.lbearing = lrint (brect.origin.x);
690 font_info->max_bounds.rbearing =
691 lrint (brect.size.width - font_info->width);
692 /*font_info->width + (font_info->ital ? 0.2 * font_info->height : 0); */
693
694 #ifdef NS_IMPL_COCOA
695 /* set up synthItal and the CG font */
696 font_info->synthItal = synthItal;
697 {
698 ATSFontRef atsFont = ATSFontFindFromPostScriptName
699 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
700
701 if (atsFont == kATSFontRefUnspecified)
702 {
703 /* see if we can get it by dropping italic (then synthesizing) */
704 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
705 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
706 fontName], kATSOptionFlagsDefault);
707 if (atsFont != kATSFontRefUnspecified)
708 font_info->synthItal = YES;
709 else
710 {
711 /* last resort fallback */
712 atsFont = ATSFontFindFromPostScriptName
713 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
714 }
715 }
716 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
717 }
718 #endif
719
720 /* set up metrics portion of font struct */
721 font->ascent = [sfont ascender];
722 font->descent = -[sfont descender];
723 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
724 font->space_width = lrint (nsfont_char_width (sfont, ' '));
725 font->average_width = lrint (font_info->width);
726 font->max_width = lrint (font_info->max_bounds.width);
727 font->height = lrint (font_info->height);
728 font->underline_position = lrint (font_info->underpos);
729 font->underline_thickness = lrint (font_info->underwidth);
730
731 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
732 font->props[FONT_FULLNAME_INDEX] =
733 make_unibyte_string (font_info->name, strlen (font_info->name));
734 }
735 UNBLOCK_INPUT;
736
737 return font_object;
738 }
739
740
741 /* Close FONT on frame F. */
742 static void
743 nsfont_close (FRAME_PTR f, struct font *font)
744 {
745 struct nsfont_info *font_info = (struct nsfont_info *)font;
746 int i;
747
748 /* FIXME: this occurs apparently due to same failure to detect same font
749 that causes need for cache in nsfont_open ()
750 (came after unicode-2 -> trunk) */
751 if (!font_info)
752 return;
753
754 for (i =0; i<0x100; i++)
755 {
756 if (font_info->glyphs[i])
757 xfree (font_info->glyphs[i]);
758 if (font_info->metrics[i])
759 xfree (font_info->metrics[i]);
760 }
761 [font_info->nsfont release];
762 #ifdef NS_IMPL_COCOA
763 CGFontRelease (font_info->cgfont);
764 #endif
765 xfree (font_info->name);
766 xfree (font_info);
767 }
768
769
770 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
771 return 1. If not, return 0. If a font must be opened to check
772 it, return -1. */
773 static int
774 nsfont_has_char (Lisp_Object entity, int c)
775 {
776 return -1;
777 }
778
779
780 /* Return a glyph code of FONT for character C (Unicode code point).
781 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
782 static unsigned int
783 nsfont_encode_char (struct font *font, int c)
784 {
785 struct nsfont_info *font_info = (struct nsfont_info *)font;
786 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
787 unsigned short g;
788
789 if (c > 0xFFFF)
790 return FONT_INVALID_CODE;
791
792 /* did we already cache this block? */
793 if (!font_info->glyphs[high])
794 ns_uni_to_glyphs (font_info, high);
795
796 g = font_info->glyphs[high][low];
797 /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */
798 return g == 0xFFFF ? FONT_INVALID_CODE : g;
799 }
800
801
802 /* Perform the size computation of glyphs of FONT and fill in members
803 of METRICS. The glyphs are specified by their glyph codes in
804 CODE (length NGLYPHS). */
805 static int
806 nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
807 struct font_metrics *metrics)
808 {
809 struct nsfont_info *font_info = (struct nsfont_info *)font;
810 struct font_metrics *pcm;
811 unsigned char high, low;
812 int totalWidth = 0;
813 int i;
814
815 bzero (metrics, sizeof (struct font_metrics));
816
817 for (i =0; i<nglyphs; i++)
818 {
819 /* get metrics for this glyph, filling cache if need be */
820 /* TODO: get metrics for whole string from an NSLayoutManager
821 (if not too slow) */
822 high = (code[i] & 0xFF00) >> 8;
823 low = code[i] & 0x00FF;
824 if (!font_info->metrics[high])
825 ns_glyph_metrics (font_info, high);
826 pcm = &(font_info->metrics[high][low]);
827
828 if (metrics->lbearing > totalWidth + pcm->lbearing)
829 metrics->lbearing = totalWidth + pcm->lbearing;
830 if (metrics->rbearing < totalWidth + pcm->rbearing)
831 metrics->rbearing = totalWidth + pcm->rbearing;
832 if (metrics->ascent < pcm->ascent)
833 metrics->ascent = pcm->ascent;
834 if (metrics->descent < pcm->descent)
835 metrics->descent = pcm->descent;
836
837 totalWidth += pcm->width;
838 }
839
840 metrics->width = totalWidth;
841
842 return totalWidth; /* not specified in doc, but xfont.c does it */
843 }
844
845
846 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
847 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
848 is nonzero, fill the background in advance. It is assured that
849 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
850 static int
851 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
852 int with_background)
853 /* NOTE: focus and clip must be set
854 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
855 {
856 static char cbuf[1024];
857 char *c = cbuf;
858 #ifdef NS_IMPL_GNUSTEP
859 static float advances[1024];
860 float *adv = advances;
861 #else
862 static CGSize advances[1024];
863 CGSize *adv = advances;
864 #endif
865 struct face *face;
866 NSRect r;
867 struct nsfont_info *font = ns_tmp_font;
868 NSColor *col, *bgCol;
869 unsigned short *t = s->char2b;
870 int i, len;
871
872 /* Select face based on input flags */
873 switch (ns_tmp_flags)
874 {
875 case NS_DUMPGLYPH_CURSOR:
876 face = s->face;
877 break;
878 case NS_DUMPGLYPH_MOUSEFACE:
879 face = FACE_FROM_ID (s->f,
880 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
881 if (!face)
882 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
883 break;
884 default:
885 face = s->face;
886 }
887
888 r.origin.x = s->x;
889 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
890 r.origin.x += abs (s->face->box_line_width);
891
892 r.origin.y = s->y;
893 r.size.height = FONT_HEIGHT (font);
894
895 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
896 NS to render the string, it will come out differently from the individual
897 character widths added up because of layout processing. */
898 {
899 XCharStruct *cs;
900 int cwidth, twidth = 0;
901 int hi, lo;
902 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
903 /* FIXME: composition: no vertical displacement is considered. */
904 t += s->cmp_from; /* advance into composition */
905 for (i = s->cmp_from; i < s->nchars; i++, t++)
906 {
907 hi = (*t & 0xFF00) >> 8;
908 lo = *t & 0x00FF;
909 if (isComposite)
910 {
911 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
912 }
913 else
914 {
915 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
916 ns_glyph_metrics (font, hi);
917 cwidth = font->metrics[hi][lo].width;
918 }
919 twidth += cwidth;
920 #ifdef NS_IMPL_GNUSTEP
921 *adv++ = cwidth;
922 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
923 #else
924 (*adv++).width = cwidth;
925 #endif
926 }
927 len = adv - advances;
928 r.size.width = twidth;
929 *c = 0;
930 }
931
932 /* fill background if requested */
933 if (with_background)
934 {
935 NSRect br = r;
936 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
937 int mbox_line_width = max (s->face->box_line_width, 0);
938
939 if (s->row->full_width_p)
940 {
941 if (br.origin.x <= fibw + 1 + mbox_line_width)
942 {
943 br.size.width += br.origin.x - mbox_line_width;
944 br.origin.x = mbox_line_width;
945 }
946 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
947 <= fibw+1)
948 br.size.width += fibw;
949 }
950 if (s->face->box == FACE_NO_BOX)
951 {
952 /* expand unboxed top row over internal border */
953 if (br.origin.y <= fibw + 1 + mbox_line_width)
954 {
955 br.size.height += br.origin.y;
956 br.origin.y = 0;
957 }
958 }
959 else
960 {
961 int correction = abs (s->face->box_line_width)+1;
962 br.origin.y += correction;
963 br.size.height -= 2*correction;
964 br.origin.x += correction;
965 br.size.width -= 2*correction;
966 }
967
968 if (!s->face->stipple)
969 [(NS_FACE_BACKGROUND (face) != 0
970 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
971 : FRAME_BACKGROUND_COLOR (s->f)) set];
972 else
973 {
974 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
975 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
976 }
977 NSRectFill (br);
978 }
979
980
981 /* set up for character rendering */
982 r.origin.y += font->voffset + (s->height - font->height)/2;
983
984 col = (NS_FACE_FOREGROUND (face) != 0
985 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
986 : FRAME_FOREGROUND_COLOR (s->f));
987 /* FIXME: find another way to pass this */
988 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
989 : (NS_FACE_BACKGROUND (face) != 0
990 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
991 : FRAME_BACKGROUND_COLOR (s->f)));
992
993 /* render under GNUstep using DPS */
994 #ifdef NS_IMPL_GNUSTEP
995 {
996 NSGraphicsContext *context = GSCurrentContext ();
997
998 DPSgsave (context);
999 [font->nsfont set];
1000
1001 /* do erase if "foreground" mode */
1002 if (bgCol != nil)
1003 {
1004 [bgCol set];
1005 DPSmoveto (context, r.origin.x, r.origin.y);
1006 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1007 DPSxshow (context, cbuf, advances, len);
1008 DPSstroke (context);
1009 [col set];
1010 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1011 }
1012
1013 /* do underline */
1014 if (face->underline_p)
1015 {
1016 if (face->underline_color != 0)
1017 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1018 else
1019 [col set];
1020 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1021 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
1022 if (face->underline_color != 0)
1023 [col set];
1024 }
1025 else
1026 [col set];
1027
1028 /* draw with DPSxshow () */
1029 DPSmoveto (context, r.origin.x, r.origin.y);
1030 DPSxshow (context, cbuf, advances, len);
1031 DPSstroke (context);
1032
1033 DPSgrestore (context);
1034 return to-from;
1035 }
1036
1037 #else /* NS_IMPL_COCOA */
1038 {
1039 CGContextRef gcontext =
1040 [[NSGraphicsContext currentContext] graphicsPort];
1041 static CGAffineTransform fliptf;
1042 static BOOL firstTime = YES;
1043
1044 if (firstTime)
1045 {
1046 firstTime = NO;
1047 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1048 }
1049
1050 CGContextSaveGState (gcontext);
1051
1052 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1053
1054 CGContextSetFont (gcontext, font->cgfont);
1055 CGContextSetFontSize (gcontext, font->size);
1056 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
1057 CGContextSetShouldAntialias (gcontext, 0);
1058 else
1059 CGContextSetShouldAntialias (gcontext, 1);
1060 if (EQ (ns_use_qd_smoothing, Qt))
1061 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1062
1063 CGContextSetTextMatrix (gcontext, fliptf);
1064
1065 if (bgCol != nil)
1066 {
1067 /* foreground drawing; erase first to avoid overstrike */
1068 [bgCol set];
1069 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1070 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1071 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1072 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1073 }
1074
1075 if (face->underline_p)
1076 {
1077 if (face->underline_color != 0)
1078 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1079 else
1080 [col set];
1081 CGContextBeginPath (gcontext);
1082 CGContextMoveToPoint (gcontext,
1083 r.origin.x, r.origin.y + font->underpos);
1084 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1085 r.origin.y + font->underpos);
1086 CGContextStrokePath (gcontext);
1087 if (face->underline_color != 0)
1088 [col set];
1089 }
1090 else
1091 [col set];
1092
1093 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1094 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1095 advances, len);
1096
1097 if (face->overstrike)
1098 {
1099 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1100 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
1101 advances, len);
1102 }
1103
1104 CGContextRestoreGState (gcontext);
1105 return;
1106 }
1107 #endif /* NS_IMPL_COCOA */
1108
1109 }
1110
1111
1112 /* Auto-creates a fontset built around the font in font_object,
1113 by creating an attributed string with characters from each
1114 script, then requesting the NS text system to fix attributes
1115 in range. */
1116 void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object)
1117 {
1118 Lisp_Object script, famAndReg;
1119 struct nsfont_info *font_info =
1120 (struct nsfont_info *)XFONT_OBJECT (font_object);
1121
1122 /* NS text system (and char buf) init */
1123 static NSTextStorage *store;
1124 static NSLayoutManager *layout;
1125 static NSRange range;
1126 static NSMutableDictionary *attribs;
1127 static Lisp_Object *scripts;
1128 static int nscripts;
1129 static int *scriptsNchars;
1130 static BOOL firstTime = YES;
1131 Lisp_Object regString = build_string ("iso10646-1");
1132 int i, j;
1133
1134 if (firstTime == YES)
1135 {
1136 nscripts = XINT (Flength (Vscript_representative_chars));
1137 scriptsNchars = (int *) malloc (nscripts * sizeof (int));
1138 unsigned char *buf = malloc (4*nscripts*sizeof (char));
1139 Lisp_Object scriptsChars = Vscript_representative_chars;
1140 unsigned char *tpos = buf;
1141
1142 scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object));
1143
1144 for (i =0; i<nscripts; i++)
1145 {
1146 Lisp_Object sChars = XCAR (scriptsChars);
1147 Lisp_Object chars = XCDR (sChars);
1148 unsigned int ch, c =0;
1149 scripts[i] = XCAR (sChars);
1150
1151 while (CONSP (chars))
1152 {
1153 ch = XUINT (XCAR (chars));
1154 chars = XCDR (chars);
1155 CHAR_STRING_ADVANCE (ch, tpos);
1156 c++;
1157 }
1158 scriptsNchars[i] = c;
1159
1160 scriptsChars = XCDR (scriptsChars);
1161 }
1162 *tpos = '\0';
1163
1164 store = [[NSTextStorage alloc] init];
1165 layout = [[NSLayoutManager alloc] init];
1166 [store addLayoutManager: layout];
1167 [layout release];
1168
1169 [store beginEditing];
1170 [[store mutableString] appendString:
1171 [NSString stringWithUTF8String: buf]];
1172 [store endEditing];
1173
1174 free (buf);
1175 range = NSMakeRange (0, [store length]);
1176
1177 attribs = [[NSMutableDictionary alloc] init];
1178 firstTime = NO;
1179 }
1180
1181 /* set the fonts */
1182 [store beginEditing];
1183 [store removeAttribute: NSFontAttributeName range: range];
1184 [attribs setObject: font_info->nsfont forKey: NSFontAttributeName];
1185 [store addAttributes: attribs range: range];
1186 [store endEditing];
1187
1188 /* read them out */
1189 {
1190 NSMutableDictionary *map =
1191 [NSMutableDictionary dictionaryWithCapacity: nscripts * 4];
1192 NSEnumerator *fonts;
1193 NSFont *cfont = nil, *tfont;
1194 NSNumber *n;
1195 int idx = 0;
1196 int max;
1197 for (i =0; i<nscripts; i++)
1198 {
1199 [map removeAllObjects];
1200 for (j =0; j<scriptsNchars[i]; j++)
1201 {
1202 cfont = [store attribute: NSFontAttributeName atIndex: idx++
1203 effectiveRange: NULL];
1204 n = [map objectForKey: cfont];
1205 if (n == nil)
1206 n = [NSNumber numberWithInt: 1];
1207 else
1208 n = [NSNumber numberWithInt: [n intValue] + 1];
1209 [map setObject: n forKey: cfont];
1210 }
1211
1212 /* majority rules */
1213 max = 0;
1214 fonts = [map keyEnumerator];
1215 while (tfont = [fonts nextObject])
1216 {
1217 n = [map objectForKey: tfont];
1218 if ([n intValue] > max)
1219 {
1220 cfont = tfont;
1221 max = [n intValue];
1222 }
1223 }
1224
1225 if (cfont != nil)
1226 {
1227 char *family = strdup([[cfont familyName] UTF8String]);
1228 Lisp_Object famAndReg;
1229
1230 nsfont_escape_name (family);
1231 famAndReg = Fcons (build_string (family), regString);
1232
1233 if (NSFONT_TRACE)
1234 fprintf (stderr, "%s fontset: use '%s' for script '%s'\n",
1235 font_info->name, family,
1236 SDATA (SYMBOL_NAME (scripts[i])));
1237
1238 /* TODO: Some of the "scripts" in script-representative-chars are
1239 actually only "sub-scripts" which are not fully defined. For
1240 these, calling set_fontset_font generates an abort. Try to
1241 guess which ones these are and avoid it. */
1242 if (strstr (SDATA (SYMBOL_NAME (scripts[i])), "mathematical-")
1243 != SDATA (SYMBOL_NAME (scripts[i])))
1244 Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1245 free (family);
1246 }
1247 else
1248 {
1249 fprintf (stderr, "%s fontset: none found for script '%s'\n",
1250 font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1251 }
1252 } /* for i = script */
1253 }
1254 }
1255
1256
1257
1258 /* ==========================================================================
1259
1260 Font glyph and metrics caching functions
1261
1262 ========================================================================== */
1263
1264 /* Find and cache corresponding glyph codes for unicode values in given
1265 hi-byte block of 256. */
1266 static void
1267 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1268 {
1269 #ifdef NS_IMPL_COCOA
1270 static EmacsGlyphStorage *glyphStorage;
1271 static char firstTime = 1;
1272 #endif
1273 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1274 unsigned int i, g, idx;
1275 unsigned short *glyphs;
1276
1277 if (NSFONT_TRACE)
1278 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1279 font_info, block);
1280
1281 BLOCK_INPUT;
1282
1283 #ifdef NS_IMPL_COCOA
1284 if (firstTime)
1285 {
1286 firstTime = 0;
1287 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1288 }
1289 #endif
1290
1291 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1292 if (!unichars || !(font_info->glyphs[block]))
1293 abort ();
1294
1295 /* create a string containing all unicode characters in this block */
1296 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1297 if (idx < 0xD800 || idx > 0xDFFF)
1298 unichars[i] = idx;
1299 else
1300 unichars[i] = 0xFEFF;
1301 unichars[0x100] = 0;
1302
1303 {
1304 #ifdef NS_IMPL_COCOA
1305 NSString *allChars = [[NSString alloc]
1306 initWithCharactersNoCopy: unichars
1307 length: 0x100
1308 freeWhenDone: NO];
1309 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1310 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1311 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1312 unsigned int gInd =0, cInd =0;
1313
1314 [glyphStorage setString: allChars font: font_info->nsfont];
1315 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1316 desiredNumberOfCharacters: glyphStorage->maxChar
1317 glyphIndex: &gInd characterIndex: &cInd];
1318 #endif
1319 glyphs = font_info->glyphs[block];
1320 for (i =0; i<0x100; i++, glyphs++)
1321 {
1322 #ifdef NS_IMPL_GNUSTEP
1323 g = unichars[i];
1324 #else
1325 g = glyphStorage->cglyphs[i];
1326 /* TODO: is this a good check? maybe need to use coveredChars.. */
1327 if (g > numGlyphs)
1328 g = 0xFFFF; /* hopefully unused... */
1329 #endif
1330 *glyphs = g;
1331 }
1332
1333 #ifdef NS_IMPL_COCOA
1334 [allChars release];
1335 #endif
1336 }
1337
1338 UNBLOCK_INPUT;
1339 xfree (unichars);
1340 }
1341
1342
1343 /* Determine and cache metrics for corresponding glyph codes in given
1344 hi-byte block of 256. */
1345 static void
1346 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1347 {
1348 unsigned int i, g;
1349 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1350 NSFont *sfont;
1351 struct font_metrics *metrics;
1352
1353 if (NSFONT_TRACE)
1354 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1355 font_info, block);
1356
1357 #ifdef NS_IMPL_GNUSTEP
1358 /* not implemented yet (as of startup 0.18), so punt */
1359 if (numGlyphs == 0)
1360 numGlyphs = 0x10000;
1361 #endif
1362
1363 BLOCK_INPUT;
1364 sfont = [font_info->nsfont screenFont];
1365
1366 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1367 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1368 if (!(font_info->metrics[block]))
1369 abort ();
1370
1371 metrics = font_info->metrics[block];
1372 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1373 {
1374 float w, lb, rb;
1375 NSRect r = [sfont boundingRectForGlyph: g];
1376
1377 #ifdef NS_IMPL_GNUSTEP
1378 {
1379 /* lord help us */
1380 NSString *s = [NSString stringWithFormat: @"%c", g];
1381 w = [sfont widthOfString: s];
1382 }
1383 #else
1384 w = [sfont advancementForGlyph: g].width;
1385 #endif
1386 w = max (w, 2.0);
1387 metrics->width = lrint (w);
1388
1389 lb = r.origin.x;
1390 rb = r.size.width - w;
1391 if (lb < 0)
1392 metrics->lbearing = round (lb);
1393 if (font_info->ital)
1394 rb += 0.22 * font_info->height;
1395 metrics->rbearing = lrint (w + rb);
1396
1397 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1398 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1399 metrics->ascent = r.size.height - metrics->descent;
1400 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1401 }
1402 UNBLOCK_INPUT;
1403 }
1404
1405
1406 #ifdef NS_IMPL_COCOA
1407 /* helper for font glyph setup */
1408 @implementation EmacsGlyphStorage
1409
1410 - init
1411 {
1412 return [self initWithCapacity: 1024];
1413 }
1414
1415 - initWithCapacity: (unsigned long) c
1416 {
1417 self = [super init];
1418 maxChar = 0;
1419 maxGlyph = 0;
1420 dict = [NSMutableDictionary new];
1421 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1422 return self;
1423 }
1424
1425 - (void) dealloc
1426 {
1427 if (attrStr != nil)
1428 [attrStr release];
1429 [dict release];
1430 xfree (cglyphs);
1431 [super dealloc];
1432 }
1433
1434 - (void) setString: (NSString *)str font: (NSFont *)font
1435 {
1436 [dict setObject: font forKey: NSFontAttributeName];
1437 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1438 maxChar = [str length];
1439 maxGlyph = 0;
1440 }
1441
1442 /* NSGlyphStorage protocol */
1443 - (unsigned int)layoutOptions
1444 {
1445 return 0;
1446 }
1447
1448 - (NSAttributedString *)attributedString
1449 {
1450 return attrStr;
1451 }
1452
1453 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1454 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1455 characterIndex: (unsigned int)charIndex
1456 {
1457 len = glyphIndex+length;
1458 for (i =glyphIndex; i<len; i++)
1459 cglyphs[i] = glyphs[i-glyphIndex];
1460 if (len > maxGlyph)
1461 maxGlyph = len;
1462 }
1463
1464 - (void)setIntAttribute: (int)attributeTag value: (int)val
1465 forGlyphAtIndex: (unsigned)glyphIndex
1466 {
1467 return;
1468 }
1469
1470 @end
1471 #endif /* NS_IMPL_COCOA */
1472
1473
1474 /* Debugging */
1475 void
1476 dump_glyphstring (struct glyph_string *s)
1477 {
1478 int i;
1479
1480 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1481 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1482 s->row->overlapping_p, s->background_filled_p);
1483 for (i =0; i<s->nchars; i++)
1484 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1485 fprintf (stderr, "\n");
1486 }
1487
1488
1489
1490 void
1491 syms_of_nsfont ()
1492 {
1493 nsfont_driver.type = Qns;
1494 register_font_driver (&nsfont_driver, NULL);
1495 DEFSYM (Qapple, "apple");
1496 DEFSYM (Qroman, "roman");
1497 DEFSYM (Qmedium, "medium");
1498 }
1499
1500 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae