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