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