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