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