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