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