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