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