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