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