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