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