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