* coding.c (make_conversion_work_buffer): Disable buffer modification
[bpt/emacs.git] / 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 /* 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 ns_expand_space;
46 extern Lisp_Object Qappend;
47 extern int ns_antialias_text, ns_use_qd_smoothing;
48 extern float ns_antialias_threshold;
49 extern int ns_tmp_flags;
50 extern struct nsfont_info *ns_tmp_font;
51
52 /* font glyph and metrics caching functions, implemented at end */
53 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
54 unsigned char block);
55 static void ns_glyph_metrics (struct nsfont_info *font_info,
56 unsigned char block);
57
58
59 /* ==========================================================================
60
61 Utilities
62
63 ========================================================================== */
64
65
66 /* Replace spaces w/another character so emacs core font parsing routines
67 aren't thrown off. */
68 static void
69 nsfont_escape_name (char *name)
70 {
71 int i =0, len =strlen (name);
72 for ( ; i<len; i++)
73 if (name[i] == ' ')
74 name[i] = '_';
75 }
76
77
78 /* Reconstruct spaces in a font family name passed through emacs. */
79 static void
80 nsfont_unescape_name (char *name)
81 {
82 int i =0, len =strlen (name);
83 for ( ; i<len; i++)
84 if (name[i] == '_')
85 name[i] = ' ';
86 }
87
88
89 /* Extract family name from a font spec. */
90 static NSString *
91 nsfont_get_family (Lisp_Object font_spec)
92 {
93 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
94 if (NILP (tem))
95 return nil;
96 else
97 {
98 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
99 NSString *family;
100 nsfont_unescape_name (tmp);
101 /* TODO: this seems to be needed only for font names that are
102 hard-coded into emacs, like 'helvetica' for splash screen */
103 if (tmp)
104 tmp[0] = toupper (tmp[0]);
105 family = [NSString stringWithUTF8String: tmp];
106 free (tmp);
107 return family;
108 }
109 }
110
111
112 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */
113 /* TODO (20080601): The font backend's strategy for handling font
114 styles continues to evolve. When/if this stabilizes, we
115 can change the code here to be more sophisticated and accurate.
116 For now, we rely on "normal/plain" style being numeric 100. */
117 #define STYLE_REF 100
118 static unsigned int
119 nsfont_spec_to_traits (Lisp_Object font_spec)
120 {
121 unsigned int traits = 0;
122 int n;
123
124 n = FONT_WEIGHT_NUMERIC (font_spec);
125 if (n != -1)
126 traits |= (n > STYLE_REF) ? NSBoldFontMask
127 : (n < STYLE_REF) ? NSUnboldFontMask : 0;
128
129 n = FONT_SLANT_NUMERIC (font_spec);
130 if (n != -1)
131 traits |= (n > STYLE_REF) ? NSItalicFontMask
132 : (n < STYLE_REF) ? NSUnitalicFontMask : 0;
133
134 n = FONT_WIDTH_NUMERIC (font_spec);
135 if (n > -1)
136 traits |= (n > STYLE_REF + 10) ? NSExpandedFontMask
137 : (n < STYLE_REF - 10) ? NSExpandedFontMask : 0;
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 (!NILP (tem) && !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 static NSMutableDictionary *fontCache = nil;
504 NSNumber *cached;
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 after font backend refactoring. */
512 if (fontCache == nil)
513 fontCache = [[NSMutableDictionary alloc] init];
514
515 if (NSFONT_TRACE)
516 {
517 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
518 debug_print (font_entity);
519 }
520
521 if (pixel_size <= 0)
522 {
523 /* try to get it out of frame params */
524 Lisp_Object tem = get_frame_param (f, Qfontsize);
525 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
526 }
527
528 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
529 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
530 9);
531 family = nsfont_get_family (font_entity);
532 if (NSFONT_TRACE)
533 {
534 fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\titalic = %d\n",
535 [family UTF8String], traits, traits & NSBoldFontMask,
536 traits & NSItalicFontMask);
537 }
538
539 /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */
540 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
541 nsfont = [fontMgr fontWithFamily: family
542 traits: traits weight: fixLeopardBug
543 size: pixel_size];
544 /* if didn't find, try synthetic italic */
545 if (nsfont == nil && synthItal && (traits & NSItalicFontMask))
546 {
547 nsfont = [fontMgr fontWithFamily: family
548 traits: traits & ~NSItalicFontMask
549 weight: fixLeopardBug size: pixel_size];
550 }
551 #ifdef NS_IMPL_COCOA
552 /* LastResort not really a family */
553 if (nsfont == nil && [@"LastResort" isEqualToString: family])
554 {
555 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
556 }
557 #endif
558
559 if (nsfont == nil)
560 {
561 message_with_string ("*** Warning: font in family '%s' not found",
562 build_string ([family UTF8String]), 1);
563 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
564 if (!nsfont)
565 {
566 fprintf (stderr, "*** Emacs.app: unable to load backup font\n");
567 return Qnil;
568 }
569 }
570
571 if (NSFONT_TRACE)
572 NSLog (@"%@\n", nsfont);
573
574 /* Check the cache */
575 cached = [fontCache objectForKey: nsfont];
576 if (cached != nil && !synthItal)
577 {
578 if (NSFONT_TRACE)
579 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
580 return (Lisp_Object)[cached unsignedLongValue];
581 }
582 else
583 {
584 font_object = font_make_object (VECSIZE (struct nsfont_info),
585 font_entity, pixel_size);
586 if (!synthItal)
587 [fontCache
588 setObject: [NSNumber numberWithUnsignedLong:
589 (unsigned long)font_object]
590 forKey: nsfont];
591 }
592
593 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
594 font = (struct font *)font_info;
595 if (!font)
596 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
597
598 font_info->glyphs = (unsigned short **)
599 xmalloc (0x100 * sizeof (unsigned short *));
600 font_info->metrics = (struct font_metrics **)
601 xmalloc (0x100 * sizeof (struct font_metrics *));
602 if (!font_info->glyphs || !font_info->metrics)
603 return Qnil;
604 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
605 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
606
607 BLOCK_INPUT;
608
609 /* for metrics */
610 sfont = [nsfont screenFont];
611 if (sfont == nil)
612 sfont = nsfont;
613
614 /* non-metric backend font struct fields */
615 font = (struct font *) font_info;
616 font->pixel_size = [sfont pointSize];
617 font->driver = &nsfont_driver;
618 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
619 font->encoding_charset = -1;
620 font->repertory_charset = -1;
621 font->default_ascent = 0;
622 font->vertical_centering = 0;
623 font->baseline_offset = 0;
624 font->relative_compose = 0;
625 font->font_encoder = NULL;
626
627 /* TODO: does anything care about this? */
628 font->props[FONT_FORMAT_INDEX] = Qns;
629 font->props[FONT_FILE_INDEX] = Qnil;
630
631 {
632 double expand, shrink, hshrink;
633 float full_height, min_height, hd;
634 const char *fontName = [[nsfont fontName] UTF8String];
635 int len = strlen (fontName);
636
637 #ifdef NS_IMPL_GNUSTEP
638 font_info->nsfont = sfont;
639 #else
640 font_info->nsfont = nsfont;
641 #endif
642 [font_info->nsfont retain];
643
644 /* set up ns_font (defined in nsgui.h) */
645 font_info->name = (char *)xmalloc (strlen (fontName)+1);
646 bcopy (fontName, font_info->name, strlen (fontName)+1);
647 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
648 font_info->ital =
649 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
650
651 /* Metrics etc.; some fonts return an unusually large max advance, so we
652 only use it for fonts that have wide characters. */
653 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
654 [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0');
655
656 brect = [sfont boundingRectForFont];
657 full_height = brect.size.height;
658 min_height = [sfont ascender] - [sfont descender];
659 hd = full_height - min_height;
660
661 if (!NUMBERP (ns_expand_space))
662 error ("No expand space defined");
663
664 /* ns_expand_space = 0.0 is use standard height; less shrink, more expand */
665 expand = XFLOATINT (ns_expand_space) + 0.5;
666
667 if (expand < 0.0)
668 {
669 shrink = 1 + expand;
670 hshrink = 1 + expand / 2.0;
671 expand = 0.0;
672 }
673 else
674 shrink = hshrink = 1.0;
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 == NO || 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 Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil);
1239 free (family);
1240 }
1241 else
1242 {
1243 fprintf (stderr, "%s fontset: none found for script '%s'\n",
1244 font_info->name, SDATA (SYMBOL_NAME (scripts[i])));
1245 }
1246 } /* for i = script */
1247 }
1248 }
1249
1250
1251
1252 /* ==========================================================================
1253
1254 Font glyph and metrics caching functions
1255
1256 ========================================================================== */
1257
1258 /* Find and cache corresponding glyph codes for unicode values in given
1259 hi-byte block of 256. */
1260 static void
1261 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1262 {
1263 #ifdef NS_IMPL_COCOA
1264 static EmacsGlyphStorage *glyphStorage;
1265 static char firstTime = 1;
1266 #endif
1267 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1268 unsigned int i, g, idx;
1269 unsigned short *glyphs;
1270
1271 if (NSFONT_TRACE)
1272 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1273 font_info, block);
1274
1275 BLOCK_INPUT;
1276
1277 #ifdef NS_IMPL_COCOA
1278 if (firstTime)
1279 {
1280 firstTime = 0;
1281 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1282 }
1283 #endif
1284
1285 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1286 if (!unichars || !(font_info->glyphs[block]))
1287 abort ();
1288
1289 /* create a string containing all unicode characters in this block */
1290 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1291 if (idx < 0xD800 || idx > 0xDFFF)
1292 unichars[i] = idx;
1293 else
1294 unichars[i] = 0xFEFF;
1295 unichars[0x100] = 0;
1296
1297 {
1298 #ifdef NS_IMPL_COCOA
1299 NSString *allChars = [[NSString alloc]
1300 initWithCharactersNoCopy: unichars
1301 length: 0x100
1302 freeWhenDone: NO];
1303 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1304 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1305 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1306 unsigned int gInd =0, cInd =0;
1307
1308 [glyphStorage setString: allChars font: font_info->nsfont];
1309 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1310 desiredNumberOfCharacters: glyphStorage->maxChar
1311 glyphIndex: &gInd characterIndex: &cInd];
1312 #endif
1313 glyphs = font_info->glyphs[block];
1314 for (i =0; i<0x100; i++, glyphs++)
1315 {
1316 #ifdef NS_IMPL_GNUSTEP
1317 g = unichars[i];
1318 #else
1319 g = glyphStorage->cglyphs[i];
1320 /* TODO: is this a good check? maybe need to use coveredChars.. */
1321 if (g > numGlyphs)
1322 g = 0xFFFF; /* hopefully unused... */
1323 #endif
1324 *glyphs = g;
1325 }
1326
1327 #ifdef NS_IMPL_COCOA
1328 [allChars release];
1329 #endif
1330 }
1331
1332 UNBLOCK_INPUT;
1333 xfree (unichars);
1334 }
1335
1336
1337 /* Determine and cache metrics for corresponding glyph codes in given
1338 hi-byte block of 256. */
1339 static void
1340 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1341 {
1342 unsigned int i, g;
1343 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1344 NSFont *sfont;
1345 struct font_metrics *metrics;
1346
1347 if (NSFONT_TRACE)
1348 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1349 font_info, block);
1350
1351 #ifdef NS_IMPL_GNUSTEP
1352 /* not implemented yet (as of startup 0.18), so punt */
1353 if (numGlyphs == 0)
1354 numGlyphs = 0x10000;
1355 #endif
1356
1357 BLOCK_INPUT;
1358 sfont = [font_info->nsfont screenFont];
1359
1360 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1361 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1362 if (!(font_info->metrics[block]))
1363 abort ();
1364
1365 metrics = font_info->metrics[block];
1366 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1367 {
1368 float w, lb, rb;
1369 NSRect r = [sfont boundingRectForGlyph: g];
1370
1371 #ifdef NS_IMPL_GNUSTEP
1372 {
1373 /* lord help us */
1374 NSString *s = [NSString stringWithFormat: @"%c", g];
1375 w = [sfont widthOfString: s];
1376 }
1377 #else
1378 w = [sfont advancementForGlyph: g].width;
1379 #endif
1380 w = max (w, 2.0);
1381 metrics->width = lrint (w);
1382
1383 lb = r.origin.x;
1384 rb = r.size.width - w;
1385 if (lb < 0)
1386 metrics->lbearing = round (lb);
1387 if (font_info->ital)
1388 rb += 0.22 * font_info->height;
1389 metrics->rbearing = lrint (w + rb);
1390
1391 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1392 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1393 metrics->ascent = r.size.height - metrics->descent;
1394 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1395 }
1396 UNBLOCK_INPUT;
1397 }
1398
1399
1400 #ifdef NS_IMPL_COCOA
1401 /* helper for font glyph setup */
1402 @implementation EmacsGlyphStorage
1403
1404 - init
1405 {
1406 return [self initWithCapacity: 1024];
1407 }
1408
1409 - initWithCapacity: (unsigned long) c
1410 {
1411 self = [super init];
1412 maxChar = 0;
1413 maxGlyph = 0;
1414 dict = [NSMutableDictionary new];
1415 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1416 return self;
1417 }
1418
1419 - (void) dealloc
1420 {
1421 if (attrStr != nil)
1422 [attrStr release];
1423 [dict release];
1424 xfree (cglyphs);
1425 [super dealloc];
1426 }
1427
1428 - (void) setString: (NSString *)str font: (NSFont *)font
1429 {
1430 [dict setObject: font forKey: NSFontAttributeName];
1431 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1432 maxChar = [str length];
1433 maxGlyph = 0;
1434 }
1435
1436 /* NSGlyphStorage protocol */
1437 - (unsigned int)layoutOptions
1438 {
1439 return 0;
1440 }
1441
1442 - (NSAttributedString *)attributedString
1443 {
1444 return attrStr;
1445 }
1446
1447 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1448 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1449 characterIndex: (unsigned int)charIndex
1450 {
1451 len = glyphIndex+length;
1452 for (i =glyphIndex; i<len; i++)
1453 cglyphs[i] = glyphs[i-glyphIndex];
1454 if (len > maxGlyph)
1455 maxGlyph = len;
1456 }
1457
1458 - (void)setIntAttribute: (int)attributeTag value: (int)val
1459 forGlyphAtIndex: (unsigned)glyphIndex
1460 {
1461 return;
1462 }
1463
1464 @end
1465 #endif /* NS_IMPL_COCOA */
1466
1467
1468 /* Debugging */
1469 void
1470 dump_glyphstring (struct glyph_string *s)
1471 {
1472 int i;
1473
1474 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:",
1475 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1476 s->row->overlapping_p, s->background_filled_p);
1477 for (i =0; i<s->nchars; i++)
1478 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1479 fprintf (stderr, "\n");
1480 }
1481
1482
1483
1484 void
1485 syms_of_nsfont ()
1486 {
1487 nsfont_driver.type = Qns;
1488 register_font_driver (&nsfont_driver, NULL);
1489 DEFSYM (Qapple, "apple");
1490 DEFSYM (Qroman, "roman");
1491 DEFSYM (Qmedium, "medium");
1492 }
1493
1494 // arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae