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