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