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