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