]> code.delx.au - gnu-emacs/blob - src/nsfont.m
; Revert "Ensure undo-boundary after insert-file-contents."
[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 (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
1075 if (!face)
1076 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1077 break;
1078 default:
1079 face = s->face;
1080 }
1081
1082 r.origin.x = s->x;
1083 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1084 r.origin.x += abs (s->face->box_line_width);
1085
1086 r.origin.y = s->y;
1087 r.size.height = FONT_HEIGHT (font);
1088
1089 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1090 NS to render the string, it will come out differently from the individual
1091 character widths added up because of layout processing. */
1092 {
1093 int cwidth, twidth = 0;
1094 int hi, lo;
1095 /* FIXME: composition: no vertical displacement is considered. */
1096 t += from; /* advance into composition */
1097 for (i = from; i < to; i++, t++)
1098 {
1099 hi = (*t & 0xFF00) >> 8;
1100 lo = *t & 0x00FF;
1101 if (isComposite)
1102 {
1103 if (!s->first_glyph->u.cmp.automatic)
1104 cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
1105 else
1106 {
1107 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1108 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
1109 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1110 cwidth = LGLYPH_WIDTH (glyph);
1111 else
1112 {
1113 cwidth = LGLYPH_WADJUST (glyph);
1114 #ifdef NS_IMPL_GNUSTEP
1115 *(adv-1) += LGLYPH_XOFF (glyph);
1116 #else
1117 (*(adv-1)).width += LGLYPH_XOFF (glyph);
1118 #endif
1119 }
1120 }
1121 }
1122 else
1123 {
1124 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
1125 ns_glyph_metrics (font, hi);
1126 cwidth = font->metrics[hi][lo].width;
1127 }
1128 twidth += cwidth;
1129 #ifdef NS_IMPL_GNUSTEP
1130 *adv++ = cwidth;
1131 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1132 #else
1133 (*adv++).width = cwidth;
1134 #endif
1135 }
1136 len = adv - advances;
1137 r.size.width = twidth;
1138 *c = 0;
1139 }
1140
1141 /* fill background if requested */
1142 if (with_background && !isComposite)
1143 {
1144 NSRect br = r;
1145 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1146 int mbox_line_width = max (s->face->box_line_width, 0);
1147
1148 if (s->row->full_width_p)
1149 {
1150 if (br.origin.x <= fibw + 1 + mbox_line_width)
1151 {
1152 br.size.width += br.origin.x - mbox_line_width;
1153 br.origin.x = mbox_line_width;
1154 }
1155 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1156 <= fibw+1)
1157 br.size.width += fibw;
1158 }
1159 if (s->face->box == FACE_NO_BOX)
1160 {
1161 /* expand unboxed top row over internal border */
1162 if (br.origin.y <= fibw + 1 + mbox_line_width)
1163 {
1164 br.size.height += br.origin.y;
1165 br.origin.y = 0;
1166 }
1167 }
1168 else
1169 {
1170 int correction = abs (s->face->box_line_width)+1;
1171 br.origin.y += correction;
1172 br.size.height -= 2*correction;
1173 br.origin.x += correction;
1174 br.size.width -= 2*correction;
1175 }
1176
1177 if (!s->face->stipple)
1178 [(NS_FACE_BACKGROUND (face) != 0
1179 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1180 : FRAME_BACKGROUND_COLOR (s->f)) set];
1181 else
1182 {
1183 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
1184 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1185 }
1186 NSRectFill (br);
1187 }
1188
1189
1190 /* set up for character rendering */
1191 r.origin.y = y;
1192
1193 col = (NS_FACE_FOREGROUND (face) != 0
1194 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1195 : FRAME_FOREGROUND_COLOR (s->f));
1196
1197 bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
1198 : (NS_FACE_BACKGROUND (face) != 0
1199 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1200 : FRAME_BACKGROUND_COLOR (s->f)));
1201
1202 /* render under GNUstep using DPS */
1203 #ifdef NS_IMPL_GNUSTEP
1204 {
1205 NSGraphicsContext *context = GSCurrentContext ();
1206
1207 DPSgsave (context);
1208 [font->nsfont set];
1209
1210 /* do erase if "foreground" mode */
1211 if (bgCol != nil)
1212 {
1213 [bgCol set];
1214 DPSmoveto (context, r.origin.x, r.origin.y);
1215 /*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1216 DPSxshow (context, (const char *) cbuf, advances, len);
1217 DPSstroke (context);
1218 [col set];
1219 /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1220 }
1221
1222 [col set];
1223
1224 /* draw with DPSxshow () */
1225 DPSmoveto (context, r.origin.x, r.origin.y);
1226 DPSxshow (context, (const char *) cbuf, advances, len);
1227 DPSstroke (context);
1228
1229 DPSgrestore (context);
1230 }
1231
1232 #else /* NS_IMPL_COCOA */
1233 {
1234 CGContextRef gcontext =
1235 [[NSGraphicsContext currentContext] graphicsPort];
1236 static CGAffineTransform fliptf;
1237 static BOOL firstTime = YES;
1238
1239 if (firstTime)
1240 {
1241 firstTime = NO;
1242 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1243 }
1244
1245 CGContextSaveGState (gcontext);
1246
1247 // Used to be Fix2X (kATSItalicQDSkew), but Fix2X is deprecated
1248 // and kATSItalicQDSkew is 0.25.
1249 fliptf.c = font->synthItal ? 0.25 : 0.0;
1250
1251 CGContextSetFont (gcontext, font->cgfont);
1252 CGContextSetFontSize (gcontext, font->size);
1253 if (NILP (ns_antialias_text) || font->size <= ns_antialias_threshold)
1254 CGContextSetShouldAntialias (gcontext, 0);
1255 else
1256 CGContextSetShouldAntialias (gcontext, 1);
1257
1258 CGContextSetTextMatrix (gcontext, fliptf);
1259
1260 if (bgCol != nil)
1261 {
1262 /* foreground drawing; erase first to avoid overstrike */
1263 [bgCol set];
1264 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1265 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1266 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1267 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1268 }
1269
1270 [col set];
1271
1272 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1273 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1274 advances, len);
1275
1276 if (face->overstrike)
1277 {
1278 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
1279 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + from,
1280 advances, len);
1281 }
1282
1283 CGContextRestoreGState (gcontext);
1284 }
1285 #endif /* NS_IMPL_COCOA */
1286
1287 unblock_input ();
1288 return to-from;
1289 }
1290
1291
1292
1293 /* ==========================================================================
1294
1295 Font glyph and metrics caching functions
1296
1297 ========================================================================== */
1298
1299 /* Find and cache corresponding glyph codes for unicode values in given
1300 hi-byte block of 256. */
1301 static void
1302 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1303 {
1304 #ifdef NS_IMPL_COCOA
1305 static EmacsGlyphStorage *glyphStorage;
1306 static char firstTime = 1;
1307 #endif
1308 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1309 unsigned int i, g, idx;
1310 unsigned short *glyphs;
1311
1312 if (NSFONT_TRACE)
1313 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1314 font_info, block);
1315
1316 block_input ();
1317
1318 #ifdef NS_IMPL_COCOA
1319 if (firstTime)
1320 {
1321 firstTime = 0;
1322 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1323 }
1324 #endif
1325
1326 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1327 if (!unichars || !(font_info->glyphs[block]))
1328 emacs_abort ();
1329
1330 /* create a string containing all Unicode characters in this block */
1331 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1332 if (idx < 0xD800 || idx > 0xDFFF)
1333 unichars[i] = idx;
1334 else
1335 unichars[i] = 0xFEFF;
1336 unichars[0x100] = 0;
1337
1338 {
1339 #ifdef NS_IMPL_COCOA
1340 NSString *allChars = [[NSString alloc]
1341 initWithCharactersNoCopy: unichars
1342 length: 0x100
1343 freeWhenDone: NO];
1344 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1345 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1346 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1347 NSUInteger gInd = 0, cInd = 0;
1348
1349 [glyphStorage setString: allChars font: font_info->nsfont];
1350 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1351 desiredNumberOfCharacters: glyphStorage->maxChar
1352 glyphIndex: &gInd characterIndex: &cInd];
1353 #endif
1354 glyphs = font_info->glyphs[block];
1355 for (i = 0; i < 0x100; i++, glyphs++)
1356 {
1357 #ifdef NS_IMPL_GNUSTEP
1358 g = unichars[i];
1359 #else
1360 g = glyphStorage->cglyphs[i];
1361 /* TODO: is this a good check? maybe need to use coveredChars.. */
1362 if (g > numGlyphs || g == NSNullGlyph)
1363 g = INVALID_GLYPH; /* hopefully unused... */
1364 #endif
1365 *glyphs = g;
1366 }
1367
1368 #ifdef NS_IMPL_COCOA
1369 [allChars release];
1370 #endif
1371 }
1372
1373 unblock_input ();
1374 xfree (unichars);
1375 }
1376
1377
1378 /* Determine and cache metrics for corresponding glyph codes in given
1379 hi-byte block of 256. */
1380 static void
1381 ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1382 {
1383 unsigned int i, g;
1384 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1385 NSFont *sfont;
1386 struct font_metrics *metrics;
1387
1388 if (NSFONT_TRACE)
1389 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1390 font_info, block);
1391
1392 #ifdef NS_IMPL_GNUSTEP
1393 /* not implemented yet (as of startup 0.18), so punt */
1394 if (numGlyphs == 0)
1395 numGlyphs = 0x10000;
1396 #endif
1397
1398 block_input ();
1399 #ifdef NS_IMPL_COCOA
1400 sfont = [font_info->nsfont screenFontWithRenderingMode:
1401 NSFontAntialiasedIntegerAdvancementsRenderingMode];
1402 #else
1403 sfont = [font_info->nsfont screenFont];
1404 #endif
1405
1406 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1407 if (!(font_info->metrics[block]))
1408 emacs_abort ();
1409
1410 metrics = font_info->metrics[block];
1411 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1412 {
1413 CGFloat w, lb, rb;
1414 NSRect r = [sfont boundingRectForGlyph: g];
1415
1416 w = max ([sfont advancementForGlyph: g].width, 2.0);
1417 metrics->width = lrint (w);
1418
1419 lb = r.origin.x;
1420 rb = r.size.width - w;
1421 // Add to bearing for LCD smoothing. We don't know if it is there.
1422 if (lb < 0)
1423 metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
1424 if (font_info->ital)
1425 rb += (CGFloat) (0.22F * font_info->height);
1426 metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
1427
1428 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1429 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1430 metrics->ascent = r.size.height - metrics->descent;
1431 /*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1432 }
1433 unblock_input ();
1434 }
1435
1436
1437 #ifdef NS_IMPL_COCOA
1438 /* helper for font glyph setup */
1439 @implementation EmacsGlyphStorage
1440
1441 - init
1442 {
1443 return [self initWithCapacity: 1024];
1444 }
1445
1446 - initWithCapacity: (unsigned long) c
1447 {
1448 self = [super init];
1449 maxChar = 0;
1450 maxGlyph = 0;
1451 dict = [NSMutableDictionary new];
1452 cglyphs = xmalloc (c * sizeof (CGGlyph));
1453 return self;
1454 }
1455
1456 - (void) dealloc
1457 {
1458 if (attrStr != nil)
1459 [attrStr release];
1460 [dict release];
1461 xfree (cglyphs);
1462 [super dealloc];
1463 }
1464
1465 - (void) setString: (NSString *)str font: (NSFont *)font
1466 {
1467 [dict setObject: font forKey: NSFontAttributeName];
1468 if (attrStr != nil)
1469 [attrStr release];
1470 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1471 maxChar = [str length];
1472 maxGlyph = 0;
1473 }
1474
1475 /* NSGlyphStorage protocol */
1476 - (NSUInteger)layoutOptions
1477 {
1478 return 0;
1479 }
1480
1481 - (NSAttributedString *)attributedString
1482 {
1483 return attrStr;
1484 }
1485
1486 - (void)insertGlyphs: (const NSGlyph *)glyphs length: (NSUInteger)length
1487 forStartingGlyphAtIndex: (NSUInteger)glyphIndex
1488 characterIndex: (NSUInteger)charIndex
1489 {
1490 len = glyphIndex+length;
1491 for (i =glyphIndex; i<len; i++)
1492 cglyphs[i] = glyphs[i-glyphIndex];
1493 if (len > maxGlyph)
1494 maxGlyph = len;
1495 }
1496
1497 - (void)setIntAttribute: (NSInteger)attributeTag value: (NSInteger)val
1498 forGlyphAtIndex: (NSUInteger)glyphIndex
1499 {
1500 return;
1501 }
1502
1503 @end
1504 #endif /* NS_IMPL_COCOA */
1505
1506
1507 /* Debugging */
1508 void
1509 ns_dump_glyphstring (struct glyph_string *s)
1510 {
1511 int i;
1512
1513 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1514 "overlap = %d, bg_filled = %d:",
1515 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1516 s->row->overlapping_p, s->background_filled_p);
1517 for (i =0; i<s->nchars; i++)
1518 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1519 fprintf (stderr, "\n");
1520 }
1521
1522
1523 void
1524 syms_of_nsfont (void)
1525 {
1526 nsfont_driver.type = Qns;
1527 register_font_driver (&nsfont_driver, NULL);
1528 DEFSYM (Qcondensed, "condensed");
1529 DEFSYM (Qexpanded, "expanded");
1530 DEFSYM (Qapple, "apple");
1531 DEFSYM (Qmedium, "medium");
1532 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1533 doc: /* Internal use: maps font registry to Unicode script. */);
1534
1535 ascii_printable = NULL;
1536 }