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