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