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