Implement token threading
[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
acaf905b 3 Copyright (C) 2006-2012 Free Software Foundation, Inc.
a68fda4a
AR
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
5a06864f
AR
23/* This should be the first include, as it may set up #defines affecting
24 interpretation of even the system includes. */
08a494a3 25#include <config.h>
b024548b 26#include <setjmp.h>
a68fda4a
AR
27
28#include "lisp.h"
29#include "dispextern.h"
30#include "composite.h"
31#include "blockinput.h"
32#include "charset.h"
33#include "frame.h"
34#include "window.h"
35#include "fontset.h"
36#include "nsterm.h"
37#include "frame.h"
38#include "character.h"
39#include "font.h"
80417b95 40#include "termchar.h"
a68fda4a 41
6e2f42b4 42/* TODO: Drop once we can assume gnustep-gui 0.17.1. */
4e2f36cf
AR
43#ifdef NS_IMPL_GNUSTEP
44#import <AppKit/NSFontDescriptor.h>
45#endif
46
a68fda4a
AR
47#define NSFONT_TRACE 0
48
49extern Lisp_Object Qns;
50extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
51static Lisp_Object Qapple, Qroman, Qmedium;
a68fda4a 52extern Lisp_Object Qappend;
a68fda4a
AR
53extern float ns_antialias_threshold;
54extern int ns_tmp_flags;
55extern struct nsfont_info *ns_tmp_font;
56
57/* font glyph and metrics caching functions, implemented at end */
58static void ns_uni_to_glyphs (struct nsfont_info *font_info,
59 unsigned char block);
60static void ns_glyph_metrics (struct nsfont_info *font_info,
61 unsigned char block);
62
63
64/* ==========================================================================
65
66 Utilities
67
68 ========================================================================== */
69
70
71/* Replace spaces w/another character so emacs core font parsing routines
72 aren't thrown off. */
73static void
8840261a 74ns_escape_name (char *name)
a68fda4a
AR
75{
76 int i =0, len =strlen (name);
77 for ( ; i<len; i++)
78 if (name[i] == ' ')
79 name[i] = '_';
80}
81
82
83/* Reconstruct spaces in a font family name passed through emacs. */
84static void
8840261a 85ns_unescape_name (char *name)
a68fda4a
AR
86{
87 int i =0, len =strlen (name);
88 for ( ; i<len; i++)
89 if (name[i] == '_')
90 name[i] = ' ';
91}
92
93
94/* Extract family name from a font spec. */
95static NSString *
8840261a 96ns_get_family (Lisp_Object font_spec)
a68fda4a
AR
97{
98 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
99 if (NILP (tem))
100 return nil;
101 else
102 {
6ca3801d 103 char *tmp = xstrdup (SDATA (SYMBOL_NAME (tem)));
a68fda4a 104 NSString *family;
8840261a 105 ns_unescape_name (tmp);
a68fda4a 106 family = [NSString stringWithUTF8String: tmp];
613052cd 107 xfree (tmp);
a68fda4a
AR
108 return family;
109 }
110}
111
112
4b7f335c
AR
113/* Return 0 if attr not set, else value (which might also be 0).
114 On Leopard 0 gets returned even on descriptors where the attribute
115 was never set, so there's no way to distinguish between unspecified
116 and set to not have. Callers should assume 0 means unspecified. */
8840261a
AR
117static float
118ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
119{
4b7f335c
AR
120 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
121 NSNumber *val = [tdict objectForKey: trait];
8840261a
AR
122 return val == nil ? 0.0 : [val floatValue];
123}
a68fda4a 124
a68fda4a 125
8840261a
AR
126/* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
127 to NSFont descriptor. Information under extra only needed for matching. */
128#define STYLE_REF 100
204ee57f
JD
129static NSFontDescriptor *
130ns_spec_to_descriptor (Lisp_Object font_spec)
8840261a
AR
131{
132 NSFontDescriptor *fdesc;
133 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
134 NSMutableDictionary *tdict = [NSMutableDictionary new];
135 NSString *family = ns_get_family (font_spec);
136 float n;
137
138 /* add each attr in font_spec to fdAttrs.. */
139 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
140 if (n != -1 && n != STYLE_REF)
141 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
142 forKey: NSFontWeightTrait];
143 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
144 if (n != -1 && n != STYLE_REF)
145 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
146 forKey: NSFontSlantTrait];
147 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
148 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
149 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
150 forKey: NSFontWidthTrait];
151 if ([tdict count] > 0)
152 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
153
154 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
38182d90 155 if (family != nil)
204ee57f 156 {
8840261a 157 fdesc = [fdesc fontDescriptorWithFamily: family];
204ee57f
JD
158 }
159
160 [fdAttrs release];
161 [tdict release];
8840261a 162 return fdesc;
a68fda4a
AR
163}
164
165
8840261a 166/* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
a68fda4a 167static Lisp_Object
9c5bd55a
J
168ns_descriptor_to_entity (NSFontDescriptor *desc,
169 Lisp_Object extra,
170 const char *style)
a68fda4a 171{
8840261a
AR
172 Lisp_Object font_entity = font_make_entity ();
173 /* NSString *psName = [desc postscriptName]; */
174 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
8840261a 175 unsigned int traits = [desc symbolicTraits];
b9173dc2 176 char *escapedFamily;
8840261a 177
b9173dc2
AR
178 /* Shouldn't happen, but on Tiger fallback desc gets name but no family. */
179 if (family == nil)
180 family = [desc objectForKey: NSFontNameAttribute];
181 if (family == nil)
182 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
183
6ca3801d 184 escapedFamily = xstrdup ([family UTF8String]);
8840261a
AR
185 ns_escape_name (escapedFamily);
186
187 ASET (font_entity, FONT_TYPE_INDEX, Qns);
188 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
189 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
190 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
191 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
192
193 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
194 traits & NSFontBoldTrait ? Qbold : Qmedium);
195/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
196 make_number (100 + 100
197 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
198 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
199 traits & NSFontItalicTrait ? Qitalic : Qnormal);
200/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
201 make_number (100 + 100
202 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
203 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
204 traits & NSFontCondensedTrait ? Qcondensed :
205 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
206/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
207 make_number (100 + 100
208 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
209
210 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
211 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
212 ASET (font_entity, FONT_SPACING_INDEX,
213 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
214 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
215
216 ASET (font_entity, FONT_EXTRA_INDEX, extra);
217 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
218
219 if (NSFONT_TRACE)
220 {
221 fprintf (stderr, "created font_entity:\n ");
222 debug_print (font_entity);
223 }
a68fda4a 224
613052cd 225 xfree (escapedFamily);
8840261a
AR
226 return font_entity;
227}
a68fda4a 228
8840261a
AR
229
230/* Default font entity. */
231static Lisp_Object
3d608a86 232ns_fallback_entity (void)
8840261a
AR
233{
234 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
235 fontDescriptor], Qnil, NULL);
a68fda4a
AR
236}
237
238
8840261a
AR
239/* Utility: get width of a char c in screen font sfont */
240static float
241ns_char_width (NSFont *sfont, int c)
a68fda4a 242{
8840261a
AR
243 float w;
244 NSString *cstr = [NSString stringWithFormat: @"%c", c];
245#ifdef NS_IMPL_COCOA
246 NSGlyph glyph = [sfont glyphWithName: cstr];
247 if (glyph)
248 {
249 float w = [sfont advancementForGlyph: glyph].width;
250 if (w >= 1.5)
251 return w;
252 }
253#endif
e28db5bc
AR
254 {
255 NSDictionary *attrsDictionary =
256 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
257 w = [cstr sizeWithAttributes: attrsDictionary].width;
258 }
8840261a
AR
259 return max (w, 2.0);
260}
261
262
263/* Return whether set1 covers set2 to a reasonable extent given by pct.
fe7a3057 264 We check, out of each 16 Unicode char range containing chars in set2,
8840261a
AR
265 whether at least one character is present in set1.
266 This must be true for pct of the pairs to consider it covering. */
267static BOOL
268ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
269{
270 const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes];
271 const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes];
272 int i, off = 0, tot = 0;
273
274 for (i=0; i<4096; i++, bytes1++, bytes2++)
275 if (*bytes2)
276 {
277 tot++;
278 if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2
279 off++;
280 }
281//fprintf(stderr, "off = %d\ttot = %d\n", off,tot);
282 return (float)off / tot < 1.0 - pct;
283}
284
285
286/* Convert :lang property to a script. Use of :lang property by font backend
287 seems to be limited for now (2009/05) to ja, zh, and ko. */
288static NSString
289*ns_lang_to_script (Lisp_Object lang)
290{
291 if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja"))
292 return @"han";
293 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
294 have more characters. */
295 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh"))
296 return @"han";
297 else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko"))
298 return @"hangul";
299 else
300 return @"";
301}
302
303
304/* Convert OTF 4-letter script code to emacs script name. (Why can't
fe7a3057 305 everyone just use some standard Unicode names for these?) */
8840261a
AR
306static NSString
307*ns_otf_to_script (Lisp_Object otf)
308{
309 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
310 return CONSP (script)
4a5885a7 311 ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (XCDR ((script))))]
8840261a
AR
312 : @"";
313}
314
315
87f66bd3
AR
316/* Convert a font registry, such as */
317static NSString
318*ns_registry_to_script (char *reg)
319{
320 Lisp_Object script, r, rts = Vns_reg_to_script;
321 while CONSP (rts)
322 {
323 r = XCAR (XCAR (rts));
324 if (!strncmp(SDATA(r), reg, strlen(SDATA(r))))
325 {
326 script = XCDR (XCAR (rts));
327 return [NSString stringWithUTF8String: SDATA (SYMBOL_NAME (script))];
328 }
329 rts = XCDR (rts);
330 }
331 return @"";
332}
333
334
335/* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
336 plus registry regular property, for something that can be mapped to a
fe7a3057 337 Unicode script. Empty string returned if no script spec found. */
8840261a
AR
338static NSString
339*ns_get_req_script (Lisp_Object font_spec)
340{
87f66bd3 341 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
8840261a
AR
342 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
343
87f66bd3 344 /* The extra-bundle properties have priority. */
8840261a
AR
345 for ( ; CONSP (extra); extra = XCDR (extra))
346 {
347 Lisp_Object tmp = XCAR (extra);
348 if (CONSP (tmp))
349 {
350 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
351 if (EQ (key, QCscript) && SYMBOLP (val))
352 return [NSString stringWithUTF8String:
353 SDATA (SYMBOL_NAME (val))];
354 if (EQ (key, QClang) && SYMBOLP (val))
355 return ns_lang_to_script (val);
356 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
357 return ns_otf_to_script (val);
358 }
359 }
87f66bd3
AR
360
361 /* If we get here, check the charset portion of the registry. */
362 if (! NILP (reg))
363 {
364 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
365 (which causes box rendering if we don't treat it like iso8858-1)
366 but also for ascii (which causes unnecessary font substitution). */
367#if 0
368 if (EQ (reg, Qiso10646_1))
369 reg = Qiso8859_1;
370#endif
371 return ns_registry_to_script (SDATA (SYMBOL_NAME (reg)));
372 }
373
8840261a
AR
374 return @"";
375}
376
377
378/* This small function is static in fontset.c. If it can be made public for
379 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
380static void
381accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
382{
383 if (EQ (XCAR (arg), val))
384 {
385 if (CONSP (range))
386 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
387 else
388 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
389 }
390}
391
392
fe7a3057 393/* Use the Unicode range information in Vchar_script_table to convert a script
8840261a
AR
394 name into an NSCharacterSet. */
395static NSCharacterSet
396*ns_script_to_charset (NSString *scriptName)
397{
398 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
399 Lisp_Object script = intern ([scriptName UTF8String]);
400 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
401
402 if (! NILP (Fmemq (script, script_list)))
403 {
404 Lisp_Object ranges, range_list;
405
406 ranges = Fcons (script, Qnil);
407 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
408 ranges);
409 range_list = Fnreverse (XCDR (ranges));
410 if (! NILP (range_list))
411 {
412 for (; CONSP (range_list); range_list = XCDR (range_list))
413 {
414 int start = XINT (XCAR (XCAR (range_list)));
415 int end = XINT (XCDR (XCAR (range_list)));
416 if (NSFONT_TRACE)
417 debug_print (XCAR (range_list));
418 if (end < 0x10000)
419 [charset addCharactersInRange:
420 NSMakeRange (start, end-start)];
421 }
422 }
423 }
424 return charset;
a68fda4a
AR
425}
426
427
8840261a
AR
428/* Return an array of font families containing characters for the given
429 script, for the given coverage criterion, including at least LastResort.
430 Results are cached by script for faster access.
431 If none are found, we reduce the percentage and try again, until 5%.
432 This provides a font with at least some characters if such can be found.
433 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
fe7a3057 434 (b) need approximate match as fonts covering full Unicode ranges are rare. */
8840261a
AR
435static NSSet
436*ns_get_covering_families (NSString *script, float pct)
437{
438 static NSMutableDictionary *scriptToFamilies = nil;
439 NSMutableSet *families;
440
441 if (NSFONT_TRACE)
442 NSLog(@"Request covering families for script: '%@'", script);
443
444 if (scriptToFamilies == nil)
e41820ee 445 scriptToFamilies = [[NSMutableDictionary alloc] init];
8840261a
AR
446
447 if ((families = [scriptToFamilies objectForKey: script]) == nil)
448 {
449 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
450 NSArray *allFamilies = [fontMgr availableFontFamilies];
451
452 if ([script length] == 0)
453 families = [NSMutableSet setWithArray: allFamilies];
454 else
455 {
456 NSCharacterSet *charset = ns_script_to_charset (script);
457 NSString *family;
458 families = [NSMutableSet setWithCapacity: 10];
459 while (1)
460 {
461 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
462 while (family = [allFamiliesEnum nextObject])
463 {
464 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
465 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
466 /* Some fonts on OS X, maybe many on GNUstep, return nil. */
467 if (fset == nil)
468 fset = [NSCharacterSet characterSetWithRange:
469 NSMakeRange (0, 127)];
470 if (ns_charset_covers(fset, charset, pct))
471 [families addObject: family];
472 }
473 pct -= 0.2;
474 if ([families count] > 0 || pct < 0.05)
475 break;
476 }
204ee57f 477 [charset release];
8840261a
AR
478 }
479#ifdef NS_IMPL_COCOA
480 if ([families count] == 0)
481 [families addObject: @"LastResort"];
482#endif
483 [scriptToFamilies setObject: families forKey: script];
484 }
485
486 if (NSFONT_TRACE)
487 NSLog(@" returning %d families", [families count]);
488 return families;
489}
490
491
492/* Implementation for list() and match(). List() can return nil, match()
493must return something. Strategy is to drop family name from attribute
494matching set for match. */
a68fda4a 495static Lisp_Object
8840261a 496ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
a68fda4a 497{
8840261a
AR
498 Lisp_Object tem, list = Qnil;
499 NSFontDescriptor *fdesc, *desc;
500 NSMutableSet *fkeys;
501 NSArray *matchingDescs;
502 NSEnumerator *dEnum;
503 NSString *family;
504 NSSet *cFamilies;
505 BOOL foundItal = NO;
506
507 if (NSFONT_TRACE)
508 {
509 fprintf (stderr, "nsfont: %s for fontspec:\n ",
510 (isMatch ? "match" : "list"));
511 debug_print (font_spec);
512 }
513
8840261a
AR
514 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
515
516 fdesc = ns_spec_to_descriptor (font_spec);
517 fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
518 if (isMatch)
519 [fkeys removeObject: NSFontFamilyAttribute];
520
521 matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
522 if (NSFONT_TRACE)
523 NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc,
524 [matchingDescs count]);
525
526 for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; )
527 {
528 if (![cFamilies containsObject:
529 [desc objectForKey: NSFontFamilyAttribute]])
530 continue;
1586503c 531 tem = ns_descriptor_to_entity (desc,
8840261a 532 AREF (font_spec, FONT_EXTRA_INDEX),
1586503c
AR
533 NULL);
534 if (isMatch)
535 return tem;
536 list = Fcons (tem, list);
e4e9c24b 537 if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
8840261a
AR
538 foundItal = YES;
539 }
540
541 /* Add synthItal member if needed. */
542 family = [fdesc objectForKey: NSFontFamilyAttribute];
4b7f335c 543 if (family != nil && !foundItal && XINT (Flength (list)) > 0)
8840261a 544 {
204ee57f
JD
545 NSFontDescriptor *s1 = [NSFontDescriptor new];
546 NSFontDescriptor *sDesc
547 = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
548 fontDescriptorWithFamily: family];
8840261a
AR
549 list = Fcons (ns_descriptor_to_entity (sDesc,
550 AREF (font_spec, FONT_EXTRA_INDEX),
551 "synthItal"), list);
204ee57f 552 [s1 release];
8840261a
AR
553 }
554
1395c6f5 555 /* Return something if was a match and nothing found. */
1586503c
AR
556 if (isMatch)
557 return ns_fallback_entity ();
1395c6f5 558
8840261a 559 if (NSFONT_TRACE)
d311d28c
PE
560 fprintf (stderr, " Returning %"pI"d entities.\n",
561 XINT (Flength (list)));
8840261a
AR
562
563 return list;
a68fda4a
AR
564}
565
566
8840261a 567
a68fda4a
AR
568/* ==========================================================================
569
570 Font driver implementation
571
572 ========================================================================== */
573
8840261a 574
a68fda4a
AR
575static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
576static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
577static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
578static Lisp_Object nsfont_list_family (Lisp_Object frame);
579static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
580 int pixel_size);
581static void nsfont_close (FRAME_PTR f, struct font *font);
582static int nsfont_has_char (Lisp_Object entity, int c);
583static unsigned int nsfont_encode_char (struct font *font, int c);
584static int nsfont_text_extents (struct font *font, unsigned int *code,
585 int nglyphs, struct font_metrics *metrics);
586static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
587 int with_background);
588
589struct font_driver nsfont_driver =
590 {
facfbbbd 591 0, /* Qns */
a68fda4a
AR
592 1, /* case sensitive */
593 nsfont_get_cache,
594 nsfont_list,
595 nsfont_match,
596 nsfont_list_family,
597 NULL, /*free_entity */
598 nsfont_open,
599 nsfont_close,
600 NULL, /* prepare_face */
601 NULL, /* done_face */
602 nsfont_has_char,
603 nsfont_encode_char,
604 nsfont_text_extents,
605 nsfont_draw,
606 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
607 anchor_point, otf_capability, otf_driver,
608 start_for_frame, end_for_frame, shape */
609 };
610
611
612/* Return a cache of font-entities on FRAME. The cache must be a
613 cons whose cdr part is the actual cache area. */
614static Lisp_Object
615nsfont_get_cache (FRAME_PTR frame)
616{
617 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
618 return (dpyinfo->name_list_element);
619}
620
621
8840261a
AR
622/* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
623 **list** of font-entities. This and match () are sole APIs that allocate
624 font-entities. Properties to be considered (2009/05/19) are:
625 regular: foundry, family, adstyle, registry
626 extended: script, lang, otf
627 "Extended" properties are not part of the vector but get stored as
628 lisp properties under FONT_EXTRA_INDEX.
629
630 The returned entities should have type set (to 'ns), plus the following:
631 foundry, family, adstyle, registry,
632 weight, slant, width, size (0 if scalable),
633 dpi, spacing, avgwidth (0 if scalable) */
a68fda4a
AR
634static Lisp_Object
635nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
636{
8840261a 637 return ns_findfonts (font_spec, NO);
a68fda4a
AR
638}
639
640
333f9019 641/* Return a font entity most closely matching with FONT_SPEC on
a68fda4a 642 FRAME. The closeness is determined by the font backend, thus
8840261a
AR
643 `face-font-selection-order' is ignored here.
644 Properties to be considered are same as for list(). */
a68fda4a
AR
645static Lisp_Object
646nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
647{
8840261a 648 return ns_findfonts(font_spec, YES);
a68fda4a
AR
649}
650
651
652/* List available families. The value is a list of family names
653 (symbols). */
654static Lisp_Object
655nsfont_list_family (Lisp_Object frame)
656{
657 Lisp_Object list = Qnil;
658 NSEnumerator *families =
659 [[[NSFontManager sharedFontManager] availableFontFamilies]
660 objectEnumerator];
661 NSString *family;
662 while (family = [families nextObject])
663 list = Fcons (intern ([family UTF8String]), list);
df2142db 664 /* FIXME: escape the name? */
a68fda4a
AR
665
666 if (NSFONT_TRACE)
d311d28c
PE
667 fprintf (stderr, "nsfont: list families returning %"pI"d entries\n",
668 XINT (Flength (list)));
a68fda4a
AR
669
670 return list;
671}
672
673
a68fda4a
AR
674/* Open a font specified by FONT_ENTITY on frame F. If the font is
675 scalable, open it with PIXEL_SIZE. */
676static Lisp_Object
677nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
678{
679 BOOL synthItal;
8840261a 680 unsigned int traits = 0;
a68fda4a
AR
681 struct nsfont_info *font_info;
682 struct font *font;
8840261a 683 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
a68fda4a
AR
684 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
685 NSString *family;
686 NSFont *nsfont, *sfont;
687 Lisp_Object tem;
688 NSRect brect;
689 Lisp_Object font_object;
690 int i;
691 int fixLeopardBug;
a68fda4a 692 static NSMutableDictionary *fontCache = nil;
8d0e382e 693 NSNumber *cached;
a68fda4a
AR
694
695 /* 2008/03/08: The same font may end up being requested for different
696 entities, due to small differences in numeric values or other issues,
697 or for different copies of the same entity. Therefore we cache to
698 avoid creating multiple struct font objects (with metrics cache, etc.)
8840261a 699 for the same NSFont object. */
a68fda4a
AR
700 if (fontCache == nil)
701 fontCache = [[NSMutableDictionary alloc] init];
a68fda4a
AR
702
703 if (NSFONT_TRACE)
704 {
705 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
706 debug_print (font_entity);
707 }
708
709 if (pixel_size <= 0)
710 {
711 /* try to get it out of frame params */
712 Lisp_Object tem = get_frame_param (f, Qfontsize);
713 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
714 }
715
716 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
717 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
718 9);
8840261a 719 family = ns_get_family (font_entity);
b9173dc2
AR
720 if (family == nil)
721 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
e4e9c24b
AR
722 /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
723 when setting family in ns_spec_to_descriptor(). */
724 if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50)
8840261a 725 traits |= NSBoldFontMask;
e4e9c24b 726 if (fabs (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05))
8840261a 727 traits |= NSItalicFontMask;
a68fda4a 728
8840261a 729 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
a68fda4a
AR
730 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
731 nsfont = [fontMgr fontWithFamily: family
732 traits: traits weight: fixLeopardBug
733 size: pixel_size];
734 /* if didn't find, try synthetic italic */
8840261a 735 if (nsfont == nil && synthItal)
a68fda4a
AR
736 {
737 nsfont = [fontMgr fontWithFamily: family
738 traits: traits & ~NSItalicFontMask
739 weight: fixLeopardBug size: pixel_size];
740 }
741#ifdef NS_IMPL_COCOA
742 /* LastResort not really a family */
743 if (nsfont == nil && [@"LastResort" isEqualToString: family])
a68fda4a 744 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
a68fda4a
AR
745#endif
746
747 if (nsfont == nil)
748 {
749 message_with_string ("*** Warning: font in family '%s' not found",
750 build_string ([family UTF8String]), 1);
751 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
a68fda4a
AR
752 }
753
8d0e382e
AR
754 if (NSFONT_TRACE)
755 NSLog (@"%@\n", nsfont);
1bc98b35 756
8d0e382e
AR
757 /* Check the cache */
758 cached = [fontCache objectForKey: nsfont];
759 if (cached != nil && !synthItal)
760 {
761 if (NSFONT_TRACE)
762 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
8840261a 763 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
86fa089e
SM
764 XHASH (font_object) = [cached unsignedLongValue];
765 return font_object;
8d0e382e
AR
766 }
767 else
768 {
769 font_object = font_make_object (VECSIZE (struct nsfont_info),
770 font_entity, pixel_size);
771 if (!synthItal)
8840261a
AR
772 [fontCache setObject: [NSNumber numberWithUnsignedLong:
773 (unsigned long) XHASH (font_object)]
774 forKey: nsfont];
8d0e382e
AR
775 }
776
777 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
8840261a 778 font = (struct font *) font_info;
8d0e382e
AR
779 if (!font)
780 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
a68fda4a 781
38182d90
PE
782 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
783 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
a68fda4a 784
8d0e382e 785 BLOCK_INPUT;
a68fda4a
AR
786
787 /* for metrics */
788 sfont = [nsfont screenFont];
789 if (sfont == nil)
790 sfont = nsfont;
791
792 /* non-metric backend font struct fields */
793 font = (struct font *) font_info;
794 font->pixel_size = [sfont pointSize];
795 font->driver = &nsfont_driver;
796 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
797 font->encoding_charset = -1;
798 font->repertory_charset = -1;
799 font->default_ascent = 0;
800 font->vertical_centering = 0;
801 font->baseline_offset = 0;
802 font->relative_compose = 0;
803 font->font_encoder = NULL;
804
a68fda4a
AR
805 font->props[FONT_FORMAT_INDEX] = Qns;
806 font->props[FONT_FILE_INDEX] = Qnil;
807
808 {
a68fda4a
AR
809 const char *fontName = [[nsfont fontName] UTF8String];
810 int len = strlen (fontName);
811
481ae085
JD
812 /* The values specified by fonts are not always exact. For
813 * example, a 6x8 font could specify that the descender is
814 * -2.00000405... (represented by 0xc000000220000000). Without
815 * adjustment, the code below would round the descender to -3,
816 * resulting in a font that would be one pixel higher than
817 * intended. */
818 CGFloat adjusted_descender = [sfont descender] + 0.0001;
819
a68fda4a
AR
820#ifdef NS_IMPL_GNUSTEP
821 font_info->nsfont = sfont;
822#else
823 font_info->nsfont = nsfont;
824#endif
825 [font_info->nsfont retain];
826
827 /* set up ns_font (defined in nsgui.h) */
38182d90 828 font_info->name = xstrdup (fontName);
a68fda4a
AR
829 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
830 font_info->ital =
831 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
832
833 /* Metrics etc.; some fonts return an unusually large max advance, so we
834 only use it for fonts that have wide characters. */
835 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
8840261a 836 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
a68fda4a
AR
837
838 brect = [sfont boundingRectForFont];
a68fda4a 839
4843aac3 840 font_info->underpos = [sfont underlinePosition];
a68fda4a
AR
841 font_info->underwidth = [sfont underlineThickness];
842 font_info->size = font->pixel_size;
a68fda4a
AR
843
844 /* max bounds */
d55e9c53 845 font_info->max_bounds.ascent = lrint ([sfont ascender]);
481ae085 846 /* Descender is usually negative. Use floor to avoid
14a225f9 847 clipping descenders. */
d55e9c53 848 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
a68fda4a
AR
849 font_info->height =
850 font_info->max_bounds.ascent + font_info->max_bounds.descent;
851 font_info->max_bounds.width = lrint (font_info->width);
852 font_info->max_bounds.lbearing = lrint (brect.origin.x);
853 font_info->max_bounds.rbearing =
854 lrint (brect.size.width - font_info->width);
a68fda4a
AR
855
856#ifdef NS_IMPL_COCOA
857 /* set up synthItal and the CG font */
858 font_info->synthItal = synthItal;
859 {
860 ATSFontRef atsFont = ATSFontFindFromPostScriptName
861 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
862
863 if (atsFont == kATSFontRefUnspecified)
864 {
865 /* see if we can get it by dropping italic (then synthesizing) */
866 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
867 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
868 fontName], kATSOptionFlagsDefault);
869 if (atsFont != kATSFontRefUnspecified)
870 font_info->synthItal = YES;
871 else
872 {
873 /* last resort fallback */
874 atsFont = ATSFontFindFromPostScriptName
875 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
876 }
877 }
878 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
879 }
880#endif
881
882 /* set up metrics portion of font struct */
14a225f9 883 font->ascent = lrint([sfont ascender]);
481ae085 884 font->descent = -lrint(floor(adjusted_descender));
e28db5bc 885 font->min_width = ns_char_width(sfont, '|');
8840261a 886 font->space_width = lrint (ns_char_width (sfont, ' '));
a68fda4a
AR
887 font->average_width = lrint (font_info->width);
888 font->max_width = lrint (font_info->max_bounds.width);
889 font->height = lrint (font_info->height);
890 font->underline_position = lrint (font_info->underpos);
891 font->underline_thickness = lrint (font_info->underwidth);
892
893 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
894 font->props[FONT_FULLNAME_INDEX] =
895 make_unibyte_string (font_info->name, strlen (font_info->name));
896 }
897 UNBLOCK_INPUT;
898
899 return font_object;
900}
901
902
903/* Close FONT on frame F. */
904static void
905nsfont_close (FRAME_PTR f, struct font *font)
906{
907 struct nsfont_info *font_info = (struct nsfont_info *)font;
908 int i;
909
df2142db 910 /* FIXME: this occurs apparently due to same failure to detect same font
8840261a 911 that causes need for cache in nsfont_open () */
a68fda4a
AR
912 if (!font_info)
913 return;
914
915 for (i =0; i<0x100; i++)
916 {
5f445726
JM
917 xfree (font_info->glyphs[i]);
918 xfree (font_info->metrics[i]);
a68fda4a
AR
919 }
920 [font_info->nsfont release];
921#ifdef NS_IMPL_COCOA
8840261a 922 CGFontRelease (font_info->cgfont);
a68fda4a 923#endif
8840261a
AR
924 xfree (font_info->name);
925 xfree (font_info);
a68fda4a
AR
926}
927
928
929/* If FONT_ENTITY has a glyph for character C (Unicode code point),
930 return 1. If not, return 0. If a font must be opened to check
931 it, return -1. */
932static int
933nsfont_has_char (Lisp_Object entity, int c)
934{
935 return -1;
936}
937
938
939/* Return a glyph code of FONT for character C (Unicode code point).
940 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
941static unsigned int
942nsfont_encode_char (struct font *font, int c)
943{
944 struct nsfont_info *font_info = (struct nsfont_info *)font;
945 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
946 unsigned short g;
947
948 if (c > 0xFFFF)
949 return FONT_INVALID_CODE;
950
951 /* did we already cache this block? */
952 if (!font_info->glyphs[high])
953 ns_uni_to_glyphs (font_info, high);
954
955 g = font_info->glyphs[high][low];
a68fda4a
AR
956 return g == 0xFFFF ? FONT_INVALID_CODE : g;
957}
958
959
960/* Perform the size computation of glyphs of FONT and fill in members
961 of METRICS. The glyphs are specified by their glyph codes in
962 CODE (length NGLYPHS). */
963static int
964nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
965 struct font_metrics *metrics)
966{
967 struct nsfont_info *font_info = (struct nsfont_info *)font;
968 struct font_metrics *pcm;
969 unsigned char high, low;
970 int totalWidth = 0;
971 int i;
972
72af86bd 973 memset (metrics, 0, sizeof (struct font_metrics));
a68fda4a
AR
974
975 for (i =0; i<nglyphs; i++)
976 {
977 /* get metrics for this glyph, filling cache if need be */
df2142db
AR
978 /* TODO: get metrics for whole string from an NSLayoutManager
979 (if not too slow) */
a68fda4a
AR
980 high = (code[i] & 0xFF00) >> 8;
981 low = code[i] & 0x00FF;
982 if (!font_info->metrics[high])
983 ns_glyph_metrics (font_info, high);
984 pcm = &(font_info->metrics[high][low]);
985
986 if (metrics->lbearing > totalWidth + pcm->lbearing)
987 metrics->lbearing = totalWidth + pcm->lbearing;
988 if (metrics->rbearing < totalWidth + pcm->rbearing)
989 metrics->rbearing = totalWidth + pcm->rbearing;
990 if (metrics->ascent < pcm->ascent)
991 metrics->ascent = pcm->ascent;
992 if (metrics->descent < pcm->descent)
993 metrics->descent = pcm->descent;
994
995 totalWidth += pcm->width;
996 }
997
998 metrics->width = totalWidth;
999
1000 return totalWidth; /* not specified in doc, but xfont.c does it */
1001}
1002
1003
1004/* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1005 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
1006 is nonzero, fill the background in advance. It is assured that
1007 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
1008static int
1009nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1010 int with_background)
1011/* NOTE: focus and clip must be set
1012 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
1013{
1014 static char cbuf[1024];
1015 char *c = cbuf;
1016#ifdef NS_IMPL_GNUSTEP
1017 static float advances[1024];
1018 float *adv = advances;
1019#else
1020 static CGSize advances[1024];
1021 CGSize *adv = advances;
1022#endif
1023 struct face *face;
1024 NSRect r;
1025 struct nsfont_info *font = ns_tmp_font;
1026 NSColor *col, *bgCol;
1027 unsigned short *t = s->char2b;
1028 int i, len;
8840261a
AR
1029 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1030 int end = isComposite ? s->cmp_to : s->nchars;
a68fda4a
AR
1031
1032 /* Select face based on input flags */
1033 switch (ns_tmp_flags)
1034 {
1035 case NS_DUMPGLYPH_CURSOR:
1036 face = s->face;
1037 break;
1038 case NS_DUMPGLYPH_MOUSEFACE:
80417b95 1039 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
a68fda4a
AR
1040 if (!face)
1041 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1042 break;
1043 default:
1044 face = s->face;
1045 }
1046
1047 r.origin.x = s->x;
1048 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1049 r.origin.x += abs (s->face->box_line_width);
1050
1051 r.origin.y = s->y;
1052 r.size.height = FONT_HEIGHT (font);
1053
1054 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1055 NS to render the string, it will come out differently from the individual
1056 character widths added up because of layout processing. */
1057 {
1058 XCharStruct *cs;
1059 int cwidth, twidth = 0;
1060 int hi, lo;
df2142db 1061 /* FIXME: composition: no vertical displacement is considered. */
81cfe31c 1062 t += s->cmp_from; /* advance into composition */
8840261a 1063 for (i = s->cmp_from; i < end; i++, t++)
a68fda4a
AR
1064 {
1065 hi = (*t & 0xFF00) >> 8;
1066 lo = *t & 0x00FF;
1067 if (isComposite)
1068 {
8840261a
AR
1069 if (!s->first_glyph->u.cmp.automatic)
1070 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1071 else
1072 {
1073 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1074 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1075 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1076 cwidth = LGLYPH_WIDTH (glyph);
1077 else
1078 {
1079 cwidth = LGLYPH_WADJUST (glyph);
1080#ifdef NS_IMPL_GNUSTEP
1081 *(adv-1) += LGLYPH_XOFF (glyph);
1082#else
1083 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1084#endif
1085 }
1086 }
a68fda4a
AR
1087 }
1088 else
1089 {
df2142db 1090 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
a68fda4a
AR
1091 ns_glyph_metrics (font, hi);
1092 cwidth = font->metrics[hi][lo].width;
1093 }
1094 twidth += cwidth;
1095#ifdef NS_IMPL_GNUSTEP
1096 *adv++ = cwidth;
1097 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1098#else
1099 (*adv++).width = cwidth;
1100#endif
1101 }
1102 len = adv - advances;
1103 r.size.width = twidth;
1104 *c = 0;
1105 }
1106
1107 /* fill background if requested */
8840261a 1108 if (with_background && !isComposite)
a68fda4a
AR
1109 {
1110 NSRect br = r;
1111 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1112 int mbox_line_width = max (s->face->box_line_width, 0);
1113
1114 if (s->row->full_width_p)
1115 {
1116 if (br.origin.x <= fibw + 1 + mbox_line_width)
1117 {
1118 br.size.width += br.origin.x - mbox_line_width;
1119 br.origin.x = mbox_line_width;
1120 }
1121 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1122 <= fibw+1)
1123 br.size.width += fibw;
1124 }
1125 if (s->face->box == FACE_NO_BOX)
1126 {
1127 /* expand unboxed top row over internal border */
1128 if (br.origin.y <= fibw + 1 + mbox_line_width)
1129 {
1130 br.size.height += br.origin.y;
1131 br.origin.y = 0;
1132 }
1133 }
1134 else
1135 {
1136 int correction = abs (s->face->box_line_width)+1;
1137 br.origin.y += correction;
1138 br.size.height -= 2*correction;
1139 br.origin.x += correction;
1140 br.size.width -= 2*correction;
1141 }
1142
1143 if (!s->face->stipple)
45d325c4 1144 [(NS_FACE_BACKGROUND (face) != 0
a68fda4a
AR
1145 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1146 : FRAME_BACKGROUND_COLOR (s->f)) set];
1147 else
1148 {
1149 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1150 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1151 }
1152 NSRectFill (br);
1153 }
1154
1155
1156 /* set up for character rendering */
d55e9c53 1157 r.origin.y = s->ybase;
a68fda4a 1158
15034960 1159 col = (NS_FACE_FOREGROUND (face) != 0
a68fda4a
AR
1160 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1161 : FRAME_FOREGROUND_COLOR (s->f));
df2142db 1162 /* FIXME: find another way to pass this */
a68fda4a 1163 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
45d325c4 1164 : (NS_FACE_BACKGROUND (face) != 0
a68fda4a
AR
1165 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1166 : FRAME_BACKGROUND_COLOR (s->f)));
1167
1168 /* render under GNUstep using DPS */
1169#ifdef NS_IMPL_GNUSTEP
1170 {
1171 NSGraphicsContext *context = GSCurrentContext ();
1172
1173 DPSgsave (context);
1174 [font->nsfont set];
1175
1176 /* do erase if "foreground" mode */
1177 if (bgCol != nil)
1178 {
1179 [bgCol set];
1180 DPSmoveto (context, r.origin.x, r.origin.y);
1181/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1182 DPSxshow (context, cbuf, advances, len);
1183 DPSstroke (context);
1184 [col set];
1185/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1186 }
1187
4843aac3 1188 [col set];
a68fda4a
AR
1189
1190 /* draw with DPSxshow () */
1191 DPSmoveto (context, r.origin.x, r.origin.y);
1192 DPSxshow (context, cbuf, advances, len);
1193 DPSstroke (context);
1194
1195 DPSgrestore (context);
a68fda4a
AR
1196 }
1197
1198#else /* NS_IMPL_COCOA */
1199 {
1200 CGContextRef gcontext =
1201 [[NSGraphicsContext currentContext] graphicsPort];
1202 static CGAffineTransform fliptf;
1203 static BOOL firstTime = YES;
1204
1205 if (firstTime)
1206 {
1207 firstTime = NO;
1208 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1209 }
1210
1211 CGContextSaveGState (gcontext);
1212
1213 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1214
1215 CGContextSetFont (gcontext, font->cgfont);
1216 CGContextSetFontSize (gcontext, font->size);
cf2fdcfb 1217 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
a68fda4a
AR
1218 CGContextSetShouldAntialias (gcontext, 0);
1219 else
1220 CGContextSetShouldAntialias (gcontext, 1);
a68fda4a
AR
1221
1222 CGContextSetTextMatrix (gcontext, fliptf);
1223
1224 if (bgCol != nil)
1225 {
1226 /* foreground drawing; erase first to avoid overstrike */
1227 [bgCol set];
1228 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1229 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1230 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1231 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1232 }
1233
4843aac3 1234 [col set];
a68fda4a
AR
1235
1236 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
93c7fcf8 1237 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
a68fda4a
AR
1238 advances, len);
1239
1240 if (face->overstrike)
1241 {
1242 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
93c7fcf8 1243 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
a68fda4a
AR
1244 advances, len);
1245 }
1246
1247 CGContextRestoreGState (gcontext);
a68fda4a
AR
1248 }
1249#endif /* NS_IMPL_COCOA */
4843aac3
AA
1250
1251 /* Draw underline, overline, strike-through. */
1252 ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x);
1253
3fdebbf9 1254 return to-from;
a68fda4a
AR
1255}
1256
1257
a68fda4a
AR
1258
1259/* ==========================================================================
1260
1261 Font glyph and metrics caching functions
1262
1263 ========================================================================== */
1264
1265/* Find and cache corresponding glyph codes for unicode values in given
1266 hi-byte block of 256. */
1267static void
1268ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1269{
1270#ifdef NS_IMPL_COCOA
1271 static EmacsGlyphStorage *glyphStorage;
1272 static char firstTime = 1;
1273#endif
1274 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1275 unsigned int i, g, idx;
1276 unsigned short *glyphs;
1277
1278 if (NSFONT_TRACE)
1279 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1280 font_info, block);
1281
1282 BLOCK_INPUT;
1283
1284#ifdef NS_IMPL_COCOA
1285 if (firstTime)
1286 {
1287 firstTime = 0;
1288 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1289 }
1290#endif
1291
1292 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1293 if (!unichars || !(font_info->glyphs[block]))
1294 abort ();
1295
fe7a3057 1296 /* create a string containing all Unicode characters in this block */
204ee57f 1297 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
a68fda4a
AR
1298 if (idx < 0xD800 || idx > 0xDFFF)
1299 unichars[i] = idx;
1300 else
1301 unichars[i] = 0xFEFF;
1302 unichars[0x100] = 0;
1303
1304 {
1305#ifdef NS_IMPL_COCOA
1306 NSString *allChars = [[NSString alloc]
1307 initWithCharactersNoCopy: unichars
1308 length: 0x100
1309 freeWhenDone: NO];
1310 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1311 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1312 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
204ee57f 1313 NSUInteger gInd = 0, cInd = 0;
a68fda4a
AR
1314
1315 [glyphStorage setString: allChars font: font_info->nsfont];
1316 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1317 desiredNumberOfCharacters: glyphStorage->maxChar
1318 glyphIndex: &gInd characterIndex: &cInd];
1319#endif
1320 glyphs = font_info->glyphs[block];
204ee57f 1321 for (i = 0; i < 0x100; i++, glyphs++)
a68fda4a
AR
1322 {
1323#ifdef NS_IMPL_GNUSTEP
1324 g = unichars[i];
1325#else
1326 g = glyphStorage->cglyphs[i];
df2142db 1327 /* TODO: is this a good check? maybe need to use coveredChars.. */
a68fda4a
AR
1328 if (g > numGlyphs)
1329 g = 0xFFFF; /* hopefully unused... */
1330#endif
1331 *glyphs = g;
1332 }
1333
1334#ifdef NS_IMPL_COCOA
1335 [allChars release];
1336#endif
1337 }
1338
1339 UNBLOCK_INPUT;
1340 xfree (unichars);
1341}
1342
1343
1344/* Determine and cache metrics for corresponding glyph codes in given
1345 hi-byte block of 256. */
1346static void
1347ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1348{
1349 unsigned int i, g;
1350 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1351 NSFont *sfont;
1352 struct font_metrics *metrics;
1353
1354 if (NSFONT_TRACE)
1355 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1356 font_info, block);
1357
1358#ifdef NS_IMPL_GNUSTEP
1359 /* not implemented yet (as of startup 0.18), so punt */
1360 if (numGlyphs == 0)
1361 numGlyphs = 0x10000;
1362#endif
1363
1364 BLOCK_INPUT;
1365 sfont = [font_info->nsfont screenFont];
1366
38182d90 1367 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
a68fda4a
AR
1368 if (!(font_info->metrics[block]))
1369 abort ();
1370
1371 metrics = font_info->metrics[block];
1372 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1373 {
1374 float w, lb, rb;
1375 NSRect r = [sfont boundingRectForGlyph: g];
1376
6e2f42b4 1377 w = max ([sfont advancementForGlyph: g].width, 2.0);
a68fda4a
AR
1378 metrics->width = lrint (w);
1379
1380 lb = r.origin.x;
1381 rb = r.size.width - w;
1382 if (lb < 0)
1383 metrics->lbearing = round (lb);
1384 if (font_info->ital)
1385 rb += 0.22 * font_info->height;
1386 metrics->rbearing = lrint (w + rb);
1387
1388 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1389 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1390 metrics->ascent = r.size.height - metrics->descent;
1391/*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1392 }
1393 UNBLOCK_INPUT;
1394}
1395
1396
1397#ifdef NS_IMPL_COCOA
1398/* helper for font glyph setup */
1399@implementation EmacsGlyphStorage
1400
1401- init
1402{
1403 return [self initWithCapacity: 1024];
1404}
1405
1406- initWithCapacity: (unsigned long) c
1407{
1408 self = [super init];
1409 maxChar = 0;
1410 maxGlyph = 0;
1411 dict = [NSMutableDictionary new];
38182d90 1412 cglyphs = xmalloc (c * sizeof (CGGlyph));
a68fda4a
AR
1413 return self;
1414}
1415
1416- (void) dealloc
1417{
1418 if (attrStr != nil)
1419 [attrStr release];
1420 [dict release];
1421 xfree (cglyphs);
1422 [super dealloc];
1423}
1424
1425- (void) setString: (NSString *)str font: (NSFont *)font
1426{
1427 [dict setObject: font forKey: NSFontAttributeName];
204ee57f
JD
1428 if (attrStr != nil)
1429 [attrStr release];
a68fda4a
AR
1430 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1431 maxChar = [str length];
1432 maxGlyph = 0;
1433}
1434
1435/* NSGlyphStorage protocol */
e28db5bc 1436- (NSUInteger)layoutOptions
a68fda4a
AR
1437{
1438 return 0;
1439}
1440
1441- (NSAttributedString *)attributedString
1442{
1443 return attrStr;
1444}
1445
e28db5bc
AR
1446- (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1447 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1448 characterIndex: (NSUInteger)charIndex
a68fda4a
AR
1449{
1450 len = glyphIndex+length;
1451 for (i =glyphIndex; i<len; i++)
1452 cglyphs[i] = glyphs[i-glyphIndex];
1453 if (len > maxGlyph)
1454 maxGlyph = len;
1455}
1456
e28db5bc
AR
1457- (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1458 forGlyphAtIndex: (NSUInteger)glyphIndex
a68fda4a
AR
1459{
1460 return;
1461}
1462
1463@end
1464#endif /* NS_IMPL_COCOA */
1465
1466
1467/* Debugging */
1468void
8840261a 1469ns_dump_glyphstring (struct glyph_string *s)
a68fda4a
AR
1470{
1471 int i;
1472
8840261a
AR
1473 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1474"overlap = %d, bg_filled = %d:",
a68fda4a
AR
1475 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1476 s->row->overlapping_p, s->background_filled_p);
1477 for (i =0; i<s->nchars; i++)
1478 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1479 fprintf (stderr, "\n");
1480}
1481
1482
a68fda4a 1483void
3d608a86 1484syms_of_nsfont (void)
a68fda4a
AR
1485{
1486 nsfont_driver.type = Qns;
1487 register_font_driver (&nsfont_driver, NULL);
1488 DEFSYM (Qapple, "apple");
1489 DEFSYM (Qroman, "roman");
1490 DEFSYM (Qmedium, "medium");
fb9d0f5a 1491 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
fe7a3057 1492 doc: /* Internal use: maps font registry to Unicode script. */);
a68fda4a 1493}