1 /* Font back-end driver for the GNUstep window system.
3 Copyright (C) 2006-2024 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
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.
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.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
20 Author: Adrian Robert (arobert@cogsci.ucsd.edu)
23 /* This should be the first include, as it may set up #defines affecting
24 interpretation of even the system includes. */
28 #include "dispextern.h"
29 #include "composite.h"
30 #include "blockinput.h"
36 #include "character.h"
41 #import <Foundation/NSException.h>
42 #import <AppKit/NSFontDescriptor.h>
43 #import <AppKit/NSLayoutManager.h>
44 #import <GNUstepGUI/GSLayoutManager.h>
45 #import <GNUstepGUI/GSFontInfo.h>
47 #define NSFONT_TRACE 0
49 /* Structure used by GS `shape' functions for storing layout
50 information for each glyph. Borrowed from macfont.h. */
51 struct ns_glyph_layout
53 /* Range of indices of the characters composed into the group of
54 glyphs that share the cursor position with this glyph. The
55 members `location' and `length' are in UTF-16 indices. */
58 /* UTF-16 index in the source string for the first character
59 associated with this glyph. */
60 NSUInteger string_index;
62 /* Horizontal and vertical adjustments of glyph position. The
63 coordinate space is that of Core Text. So, the `baseline_delta'
64 value is negative if the glyph should be placed below the
66 CGFloat advance_delta, baseline_delta;
68 /* Typographical width of the glyph. */
71 /* Glyph ID of the glyph. */
76 enum lgstring_direction
78 DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1
84 GS_FONT_SLANT_REVERSE_ITALIC,
97 GS_FONT_WIDTH_CONDENSED,
98 GS_FONT_WIDTH_EXPANDED,
104 GS_SPECIFIED_SLANT = 1,
105 GS_SPECIFIED_WEIGHT = 1 << 1,
106 GS_SPECIFIED_WIDTH = 1 << 2,
107 GS_SPECIFIED_FAMILY = 1 << 3,
108 GS_SPECIFIED_SPACING = 1 << 4
114 enum gs_font_slant slant;
115 enum gs_font_weight weight;
116 enum gs_font_width width;
122 ns_done_font_data (struct gs_font_data *data)
124 if (data->specified & GS_SPECIFIED_FAMILY)
125 xfree (data->family_name);
129 ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat)
132 NSFontSymbolicTraits traits = [desc symbolicTraits];
133 NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute];
134 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
140 dat->specified |= GS_SPECIFIED_FAMILY;
141 dat->family_name = xstrdup ([family cStringUsingEncoding: NSUTF8StringEncoding]);
144 tem = [desc objectForKey: NSFontFixedAdvanceAttribute];
146 if ((tem != nil && [tem boolValue] != NO)
147 || (traits & NSFontMonoSpaceTrait))
149 dat->specified |= GS_SPECIFIED_SPACING;
150 dat->monospace_p = true;
152 else if (tem != nil && [tem boolValue] == NO)
154 dat->specified |= GS_SPECIFIED_SPACING;
155 dat->monospace_p = false;
158 if (traits & NSFontBoldTrait)
160 dat->specified |= GS_SPECIFIED_WEIGHT;
161 dat->weight = GS_FONT_WEIGHT_BOLD;
164 if (traits & NSFontItalicTrait)
166 dat->specified |= GS_SPECIFIED_SLANT;
167 dat->slant = GS_FONT_SLANT_ITALIC;
170 if (traits & NSFontCondensedTrait)
172 dat->specified |= GS_SPECIFIED_WIDTH;
173 dat->width = GS_FONT_WIDTH_CONDENSED;
175 else if (traits & NSFontExpandedTrait)
177 dat->specified |= GS_SPECIFIED_WIDTH;
178 dat->width = GS_FONT_WIDTH_EXPANDED;
183 tem = [dict objectForKey: NSFontSlantTrait];
187 dat->specified |= GS_SPECIFIED_SLANT;
189 dat->slant = [tem floatValue] > 0
190 ? GS_FONT_SLANT_ITALIC
191 : ([tem floatValue] < 0
192 ? GS_FONT_SLANT_REVERSE_ITALIC
193 : GS_FONT_SLANT_NORMAL);
196 tem = [dict objectForKey: NSFontWeightTrait];
200 dat->specified |= GS_SPECIFIED_WEIGHT;
202 dat->weight = [tem floatValue] > 0
203 ? GS_FONT_WEIGHT_BOLD
204 : ([tem floatValue] < -0.4f
205 ? GS_FONT_WEIGHT_LIGHT
206 : GS_FONT_WEIGHT_NORMAL);
209 tem = [dict objectForKey: NSFontWidthTrait];
213 dat->specified |= GS_SPECIFIED_WIDTH;
215 dat->width = [tem floatValue] > 0
216 ? GS_FONT_WIDTH_EXPANDED
217 : ([tem floatValue] < 0
218 ? GS_FONT_WIDTH_NORMAL
219 : GS_FONT_WIDTH_CONDENSED);
225 ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target)
227 struct gs_font_data dat;
228 struct gs_font_data t;
230 ns_get_font_data (desc, &dat);
231 ns_get_font_data (target, &t);
233 if (!(t.specified & GS_SPECIFIED_WIDTH))
234 t.width = GS_FONT_WIDTH_NORMAL;
235 if (!(t.specified & GS_SPECIFIED_WEIGHT))
236 t.weight = GS_FONT_WEIGHT_NORMAL;
237 if (!(t.specified & GS_SPECIFIED_SPACING))
238 t.monospace_p = false;
239 if (!(t.specified & GS_SPECIFIED_SLANT))
240 t.slant = GS_FONT_SLANT_NORMAL;
242 if (!(t.specified & GS_SPECIFIED_FAMILY))
247 if (dat.specified & GS_SPECIFIED_WIDTH
248 && dat.width != t.width)
254 if (dat.specified & GS_SPECIFIED_WEIGHT
255 && dat.weight != t.weight)
261 if (dat.specified & GS_SPECIFIED_SPACING
262 && dat.monospace_p != t.monospace_p)
268 if (dat.specified & GS_SPECIFIED_SLANT
269 && dat.monospace_p != t.monospace_p)
272 printf ("Matching monospace for %s: %d %d\n",
273 t.family_name, dat.monospace_p,
279 if (dat.specified & GS_SPECIFIED_FAMILY
280 && strcmp (dat.family_name, t.family_name))
284 ns_done_font_data (&dat);
285 ns_done_font_data (&t);
290 /* Font glyph and metrics caching functions, implemented at end. */
291 static void ns_uni_to_glyphs (struct nsfont_info *font_info,
292 unsigned char block);
293 static void ns_glyph_metrics (struct nsfont_info *font_info,
296 #define INVALID_GLYPH 0xFFFF
298 /* ==========================================================================
302 ========================================================================== */
305 /* Extract family name from a font spec. */
307 ns_get_family (Lisp_Object font_spec)
309 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
314 char *tmp = xlispstrdup (SYMBOL_NAME (tem));
316 family = [NSString stringWithUTF8String: tmp];
322 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
323 to NSFont descriptor. Information under extra only needed for matching. */
324 static NSFontDescriptor *
325 ns_spec_to_descriptor (Lisp_Object font_spec)
327 NSFontDescriptor *fdesc;
328 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
329 NSString *family = ns_get_family (font_spec);
330 NSMutableDictionary *tdict = [NSMutableDictionary new];
334 tem = FONT_SLANT_SYMBOLIC (font_spec);
337 if (EQ (tem, Qitalic) || EQ (tem, Qoblique))
338 [tdict setObject: [NSNumber numberWithFloat: 1.0]
339 forKey: NSFontSlantTrait];
340 else if (EQ (tem, Qreverse_italic)
341 || EQ (tem, Qreverse_oblique))
342 [tdict setObject: [NSNumber numberWithFloat: -1.0]
343 forKey: NSFontSlantTrait];
345 [tdict setObject: [NSNumber numberWithFloat: 0.0]
346 forKey: NSFontSlantTrait];
349 tem = FONT_WIDTH_SYMBOLIC (font_spec);
352 if (EQ (tem, Qcondensed))
353 [tdict setObject: [NSNumber numberWithFloat: -1.0]
354 forKey: NSFontWidthTrait];
355 else if (EQ (tem, Qexpanded))
356 [tdict setObject: [NSNumber numberWithFloat: 1.0]
357 forKey: NSFontWidthTrait];
359 [tdict setObject: [NSNumber numberWithFloat: 0.0]
360 forKey: NSFontWidthTrait];
363 tem = FONT_WEIGHT_SYMBOLIC (font_spec);
369 [tdict setObject: [NSNumber numberWithFloat: 1.0]
370 forKey: NSFontWeightTrait];
372 else if (EQ (tem, Qlight))
374 [tdict setObject: [NSNumber numberWithFloat: -1.0]
375 forKey: NSFontWeightTrait];
379 [tdict setObject: [NSNumber numberWithFloat: 0.0]
380 forKey: NSFontWeightTrait];
384 tem = AREF (font_spec, FONT_SPACING_INDEX);
387 [fdAttrs setObject: family
388 forKey: NSFontFamilyAttribute];
392 if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL)
393 [fdAttrs setObject: [NSNumber numberWithBool: YES]
394 forKey: NSFontFixedAdvanceAttribute];
396 [fdAttrs setObject: [NSNumber numberWithBool: NO]
397 forKey: NSFontFixedAdvanceAttribute];
400 /* Handle special families such as ``fixed'', ``monospace'' or
403 if ([family isEqualToString: @"fixed"]
404 || [family isEqualToString: @"monospace"])
405 [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName]
406 forKey: NSFontFamilyAttribute];
407 else if ([family isEqualToString: @"Sans Serif"])
408 [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName]
409 forKey: NSFontFamilyAttribute];
411 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
413 fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
414 retain] autorelease];
422 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc. */
424 ns_descriptor_to_entity (NSFontDescriptor *desc,
428 Lisp_Object font_entity = font_make_entity ();
429 struct gs_font_data data;
430 ns_get_font_data (desc, &data);
432 ASET (font_entity, FONT_TYPE_INDEX, Qns);
433 ASET (font_entity, FONT_FOUNDRY_INDEX, Qns);
434 if (data.specified & GS_SPECIFIED_FAMILY)
435 ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name));
436 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
437 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
439 if (data.specified & GS_SPECIFIED_WEIGHT)
441 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
442 data.weight == GS_FONT_WEIGHT_BOLD
443 ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT
444 ? Qlight : Qnormal));
447 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal);
449 if (data.specified & GS_SPECIFIED_SLANT)
451 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
452 data.slant == GS_FONT_SLANT_ITALIC
453 ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC
454 ? Qreverse_italic : Qnormal));
457 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal);
459 if (data.specified & GS_SPECIFIED_WIDTH)
461 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
462 data.width == GS_FONT_WIDTH_CONDENSED
463 ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED
464 ? Qexpanded : Qnormal));
467 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal);
469 ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0));
470 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
471 ASET (font_entity, FONT_SPACING_INDEX,
472 make_fixnum ((data.specified & GS_SPECIFIED_SPACING && data.monospace_p)
473 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
475 ASET (font_entity, FONT_EXTRA_INDEX, extra);
476 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
480 fputs ("created font_entity:\n ", stderr);
481 debug_print (font_entity);
484 ns_done_font_data (&data);
489 /* Default font entity. */
491 ns_fallback_entity (void)
493 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] fontDescriptor], Qnil, NULL);
497 /* Utility: get width of a char c in screen font SFONT. */
499 ns_char_width (NSFont *sfont, int c)
502 NSString *cstr = [NSString stringWithFormat: @"%c", c];
506 NSDictionary *attrsDictionary =
507 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
508 w = [cstr sizeWithAttributes: attrsDictionary].width;
514 /* Return average width over ASCII printable characters for SFONT. */
516 static NSString *ascii_printable;
519 ns_ascii_average_width (NSFont *sfont)
523 if (!ascii_printable)
527 for (ch = 0; ch < 95; ch++)
528 chars[ch] = ' ' + ch;
531 ascii_printable = [[NSString alloc] initWithFormat: @"%s", chars];
534 if (w < (CGFloat) 0.0)
536 NSDictionary *attrsDictionary =
537 [NSDictionary dictionaryWithObject: sfont forKey: NSFontAttributeName];
538 w = [ascii_printable sizeWithAttributes: attrsDictionary].width;
541 return lrint (w / (CGFloat) 95.0);
545 /* Return whether set1 covers set2 to a reasonable extent given by pct.
547 The GNUstep bitmap representation doesn't match Apple's
548 description. It appears to be a single block of bytes, not broken
549 up into planes, where the last byte contains the highest character
550 the character set supports. */
552 ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct)
554 NSData *font = [set1 bitmapRepresentation];
555 NSData *script = [set2 bitmapRepresentation];
557 uint8_t *fontPlane = (uint8_t *)[font bytes];
558 uint8_t *scriptPlane = (uint8_t *)[script bytes];
560 int covered = 0, total = 0;
562 for (ptrdiff_t b = 0 ; b < [script length] ; b++)
563 for (int i = 0 ; i < 8 ; i++)
565 if (*(scriptPlane + b) & (1 << i))
569 if (b < [font length]
570 && *(fontPlane + b) & (1 << i))
575 return (float)covered / total >= 1.0F - pct;
579 /* Convert :lang property to a script. Use of :lang property by font backend
580 seems to be limited for now (2009/05) to ja, zh, and ko. */
582 *ns_lang_to_script (Lisp_Object lang)
584 if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ja"))
586 /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts
587 have more characters. */
588 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "zh"))
590 else if (!strcmp (SSDATA (SYMBOL_NAME (lang)), "ko"))
597 /* Convert OTF 4-letter script code to emacs script name. (Why can't
598 everyone just use some standard Unicode names for these?) */
600 *ns_otf_to_script (Lisp_Object otf)
602 Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist);
603 return CONSP (script)
604 ? [NSString stringWithLispString: SYMBOL_NAME (XCDR (script))]
609 /* Convert a font registry. */
611 *ns_registry_to_script (char *reg)
613 Lisp_Object script, r, rts = Vns_reg_to_script;
616 r = XCAR (XCAR (rts));
617 if (!strncmp (SSDATA (r), reg, SBYTES (r)))
619 script = XCDR (XCAR (rts));
620 return [NSString stringWithLispString: SYMBOL_NAME (script)];
628 /* Searches the :script, :lang, and :otf extra-bundle properties of the spec,
629 plus registry regular property, for something that can be mapped to a
630 Unicode script. Empty string returned if no script spec found. */
632 *ns_get_req_script (Lisp_Object font_spec)
634 Lisp_Object reg = AREF (font_spec, FONT_REGISTRY_INDEX);
635 Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX);
637 /* The extra-bundle properties have priority. */
638 for ( ; CONSP (extra); extra = XCDR (extra))
640 Lisp_Object tmp = XCAR (extra);
643 Lisp_Object key = XCAR (tmp), val = XCDR (tmp);
644 if (EQ (key, QCscript) && SYMBOLP (val))
645 return [NSString stringWithLispString: SYMBOL_NAME (val)];
646 if (EQ (key, QClang) && SYMBOLP (val))
647 return ns_lang_to_script (val);
648 if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val)))
649 return ns_otf_to_script (val);
653 /* If we get here, check the charset portion of the registry. */
656 /* XXX: iso10646 is passed in for non-ascii latin-1 characters
657 (which causes box rendering if we don't treat it like iso8858-1)
658 but also for ascii (which causes unnecessary font substitution). */
660 if (EQ (reg, Qiso10646_1))
663 return ns_registry_to_script (SSDATA (SYMBOL_NAME (reg)));
670 /* This small function is static in fontset.c. If it can be made public for
671 all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */
673 accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val)
675 if (EQ (XCAR (arg), val))
678 XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
680 XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
685 /* Use the Unicode range information in Vchar_script_table to convert a script
686 name into an NSCharacterSet. */
687 static NSCharacterSet
688 *ns_script_to_charset (NSString *scriptName)
690 NSMutableCharacterSet *charset = [NSMutableCharacterSet new];
691 Lisp_Object script = intern ([scriptName UTF8String]);
692 Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
694 if (! NILP (Fmemq (script, script_list)))
696 Lisp_Object ranges, range_list;
698 ranges = list1 (script);
699 map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
701 range_list = Fnreverse (XCDR (ranges));
702 if (! NILP (range_list))
704 for (; CONSP (range_list); range_list = XCDR (range_list))
706 int start = XFIXNUM (XCAR (XCAR (range_list)));
707 int end = XFIXNUM (XCDR (XCAR (range_list)));
709 debug_print (XCAR (range_list));
711 [charset addCharactersInRange:
712 NSMakeRange (start, end-start)];
720 /* Return an array of font families containing characters for the given
721 script, for the given coverage criterion, including at least LastResort.
722 Results are cached by script for faster access.
723 If none are found, we reduce the percentage and try again, until 5%.
724 This provides a font with at least some characters if such can be found.
725 We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and
726 (b) need approximate match as fonts covering full Unicode ranges are rare. */
728 *ns_get_covering_families (NSString *script, float pct)
730 static NSMutableDictionary *scriptToFamilies = nil;
731 NSMutableSet *families;
734 NSLog(@"Request covering families for script: '%@'", script);
736 if (scriptToFamilies == nil)
737 scriptToFamilies = [[NSMutableDictionary alloc] init];
739 if ((families = [scriptToFamilies objectForKey: script]) == nil)
741 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
742 NSArray *allFamilies = [fontMgr availableFontFamilies];
744 if ([script length] == 0)
745 families = [NSMutableSet setWithArray: allFamilies];
748 NSCharacterSet *charset = ns_script_to_charset (script);
750 families = [NSMutableSet setWithCapacity: 10];
753 NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator];
754 while ((family = [allFamiliesEnum nextObject]))
756 NSCharacterSet *fset = [[fontMgr fontWithFamily: family
757 traits: 0 weight: 5 size: 12.0] coveredCharacterSet];
758 /* Some fonts on macOS, maybe many on GNUstep, return nil. */
760 fset = [NSCharacterSet characterSetWithRange:
761 NSMakeRange (0, 127)];
762 if (ns_charset_covers(fset, charset, pct))
763 [families addObject: family];
766 if ([families count] > 0 || pct < 0.05F)
771 [scriptToFamilies setObject: families forKey: script];
775 NSLog(@" returning %lu families", (unsigned long)[families count]);
779 /* GNUstep font matching is very mediocre (it can't even compare
780 symbolic styles correctly), which is why our own font matching
781 mechanism must be implemented. */
783 /* Implementation for list and match. */
785 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
787 Lisp_Object tem, list = Qnil;
788 NSFontDescriptor *fdesc;
790 GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator];
797 fprintf (stderr, "nsfont: %s for fontspec:\n ",
798 (isMatch ? "match" : "list"));
799 debug_print (font_spec);
802 cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
804 fdesc = ns_spec_to_descriptor (font_spec);
805 all_descs = [enumerator availableFontDescriptors];
807 for (NSFontDescriptor *desc in all_descs)
809 if (![cFamilies containsObject:
810 [desc objectForKey: NSFontFamilyAttribute]])
812 if (!ns_font_descs_match_p (fdesc, desc))
815 tem = ns_descriptor_to_entity (desc,
816 AREF (font_spec, FONT_EXTRA_INDEX),
820 list = Fcons (tem, list);
825 /* Return something if was a match and nothing found. */
827 return ns_fallback_entity ();
830 fprintf (stderr, " Returning %"pD"d entities.\n",
838 /* ==========================================================================
840 Font driver implementation
842 ========================================================================== */
845 /* Return a cache of font-entities on FRAME. The cache must be a
846 cons whose cdr part is the actual cache area. */
848 nsfont_get_cache (struct frame *frame)
850 Display_Info *dpyinfo = FRAME_DISPLAY_INFO (frame);
851 return (dpyinfo->name_list_element);
855 /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
856 **list** of font-entities. This and match () are sole APIs that allocate
857 font-entities. Properties to be considered (2009/05/19) are:
858 regular: foundry, family, adstyle, registry
859 extended: script, lang, otf
860 "Extended" properties are not part of the vector but get stored as
861 lisp properties under FONT_EXTRA_INDEX.
863 The returned entities should have type set (to 'ns), plus the following:
864 foundry, family, adstyle, registry,
865 weight, slant, width, size (0 if scalable),
866 dpi, spacing, avgwidth (0 if scalable) */
868 nsfont_list (struct frame *f, Lisp_Object font_spec)
870 return ns_findfonts (font_spec, NO);
874 /* Return a font entity most closely matching with FONT_SPEC on
875 FRAME. The closeness is determined by the font backend, thus
876 `face-font-selection-order' is ignored here.
877 Properties to be considered are same as for list(). */
879 nsfont_match (struct frame *f, Lisp_Object font_spec)
881 return ns_findfonts (font_spec, YES);
885 /* List available families. The value is a list of family names
888 nsfont_list_family (struct frame *f)
890 Lisp_Object list = Qnil;
891 NSEnumerator *families;
895 families = [[[NSFontManager sharedFontManager] availableFontFamilies]
897 while ((family = [families nextObject]))
898 list = Fcons (intern ([family UTF8String]), list);
901 fprintf (stderr, "nsfont: list families returning %"pD"d entries\n",
909 /* Open a font specified by FONT_ENTITY on frame F. If the font is
910 scalable, open it with PIXEL_SIZE. */
912 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
914 struct nsfont_info *font_info;
916 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
917 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
919 NSFont *nsfont, *sfont;
921 Lisp_Object font_object;
928 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
929 debug_print (font_entity);
934 /* try to get it out of frame params */
935 tem = get_frame_param (f, Qfontsize);
936 pixel_size = NILP (tem) ? 0 : XFIXNAT (tem);
939 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
940 family = ns_get_family (font_entity);
942 family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
944 nsfont = [NSFont fontWithDescriptor: fontDesc
948 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
951 NSLog (@"%@\n", nsfont);
953 font_object = font_make_object (VECSIZE (struct nsfont_info),
954 font_entity, pixel_size);
955 ASET (font_object, FONT_TYPE_INDEX, Qns);
956 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
957 font = (struct font *) font_info;
964 font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
965 font_info->metrics = xzalloc (0x100 * sizeof *font_info->metrics);
968 sfont = [nsfont screenFont];
973 /* non-metric backend font struct fields */
974 font = (struct font *) font_info;
975 font->pixel_size = [sfont pointSize];
976 font->driver = &nsfont_driver;
977 font->encoding_charset = -1;
978 font->repertory_charset = -1;
979 font->default_ascent = 0;
980 font->vertical_centering = 0;
981 font->baseline_offset = 0;
982 font->relative_compose = 0;
985 const char *fontName = [[nsfont fontName] UTF8String];
987 /* The values specified by fonts are not always exact. For
988 * example, a 6x8 font could specify that the descender is
989 * -2.00000405... (represented by 0xc000000220000000). Without
990 * adjustment, the code below would round the descender to -3,
991 * resulting in a font that would be one pixel higher than
993 CGFloat adjusted_descender = [sfont descender] + 0.0001;
995 font_info->nsfont = sfont;
996 [font_info->nsfont retain];
998 /* set up ns_font (defined in nsgui.h) */
999 font_info->name = xstrdup (fontName);
1000 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
1002 ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
1004 /* Metrics etc.; some fonts return an unusually large max advance, so we
1005 only use it for fonts that have wide characters. */
1006 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
1007 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
1009 brect = [sfont boundingRectForFont];
1011 font_info->underpos = [sfont underlinePosition];
1012 font_info->underwidth = [sfont underlineThickness];
1013 font_info->size = font->pixel_size;
1016 font->ascent = font_info->max_bounds.ascent = lrint ([sfont ascender]);
1017 /* Descender is usually negative. Use floor to avoid
1018 clipping descenders. */
1020 font_info->max_bounds.descent = -lrint (floor(adjusted_descender));
1022 font_info->max_bounds.ascent + font_info->max_bounds.descent;
1023 font_info->max_bounds.width = lrint (font_info->width);
1024 font_info->max_bounds.lbearing = lrint (brect.origin.x);
1025 font_info->max_bounds.rbearing =
1026 lrint (brect.size.width - (CGFloat) font_info->width);
1028 /* set up metrics portion of font struct */
1029 font->space_width = lrint (ns_char_width (sfont, ' '));
1030 font->max_width = lrint (font_info->max_bounds.width);
1031 font->min_width = font->space_width; /* Approximate. */
1032 font->average_width = ns_ascii_average_width (sfont);
1034 font->height = lrint (font_info->height);
1035 font->underline_position = lrint (font_info->underpos);
1036 font->underline_thickness = lrint (font_info->underwidth);
1038 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil, Qnil);
1039 font->props[FONT_FULLNAME_INDEX] = build_unibyte_string (font_info->name);
1049 nsfont_close (struct font *font)
1051 struct nsfont_info *font_info = (struct nsfont_info *) font;
1053 /* FIXME: font_info may be NULL due to same failure to detect
1054 same font that causes need for cache in nsfont_open. */
1055 if (font_info && font_info->name)
1059 for (i = 0; i < 0x100; i++)
1061 xfree (font_info->glyphs[i]);
1062 xfree (font_info->metrics[i]);
1064 xfree (font_info->glyphs);
1065 xfree (font_info->metrics);
1066 [font_info->nsfont release];
1067 xfree (font_info->name);
1068 font_info->name = NULL;
1073 /* If FONT_ENTITY has a glyph for character C (Unicode code point),
1074 return 1. If not, return 0. If a font must be opened to check
1077 nsfont_has_char (Lisp_Object entity, int c)
1083 /* Return a glyph code of FONT for character C (Unicode code point).
1084 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
1086 nsfont_encode_char (struct font *font, int c)
1088 struct nsfont_info *font_info = (struct nsfont_info *)font;
1089 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
1093 return FONT_INVALID_CODE;
1095 /* Did we already cache this block? */
1096 if (!font_info->glyphs[high])
1097 ns_uni_to_glyphs (font_info, high);
1099 g = font_info->glyphs[high][low];
1100 return g == INVALID_GLYPH ? FONT_INVALID_CODE : g;
1104 /* Perform the size computation of glyphs of FONT and fill in members
1105 of METRICS. The glyphs are specified by their glyph codes in
1106 CODE (length NGLYPHS). */
1108 nsfont_text_extents (struct font *font, const unsigned int *code,
1109 int nglyphs, struct font_metrics *metrics)
1111 struct nsfont_info *font_info = (struct nsfont_info *)font;
1112 struct font_metrics *pcm;
1113 unsigned char high, low;
1117 memset (metrics, 0, sizeof (struct font_metrics));
1119 for (i = 0; i < nglyphs; i++)
1121 /* get metrics for this glyph, filling cache if need be */
1122 /* TODO: get metrics for whole string from an NSLayoutManager
1123 (if not too slow) */
1124 high = (code[i] & 0xFF00) >> 8;
1125 low = code[i] & 0x00FF;
1126 if (!font_info->metrics[high])
1127 ns_glyph_metrics (font_info, high);
1128 pcm = &(font_info->metrics[high][low]);
1130 if (metrics->lbearing > totalWidth + pcm->lbearing)
1131 metrics->lbearing = totalWidth + pcm->lbearing;
1132 if (metrics->rbearing < totalWidth + pcm->rbearing)
1133 metrics->rbearing = totalWidth + pcm->rbearing;
1134 if (metrics->ascent < pcm->ascent)
1135 metrics->ascent = pcm->ascent;
1136 if (metrics->descent < pcm->descent)
1137 metrics->descent = pcm->descent;
1139 totalWidth += pcm->width;
1142 metrics->width = totalWidth;
1146 /* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
1147 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
1148 fill the background in advance. It is assured that WITH_BACKGROUND
1149 is false when (FROM > 0 || TO < S->nchars). */
1151 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
1152 bool with_background)
1154 NSGlyph *c = alloca ((to - from) * sizeof *c);
1158 struct nsfont_info *font;
1160 int len = to - from;
1161 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
1165 font = (struct nsfont_info *) s->font;
1167 font = (struct nsfont_info *)FRAME_FONT (s->f);
1173 r.size.height = FONT_HEIGHT (font);
1175 for (int i = 0; i < len; ++i)
1176 c[i] = s->char2b[i + from];
1178 /* Fill background if requested. */
1179 if (with_background && !isComposite)
1181 NSRect br = NSMakeRect (x, y - FONT_BASE (s->font),
1182 s->width, FONT_HEIGHT (s->font));
1183 if (s->hl != DRAW_CURSOR)
1184 [(NS_FACE_BACKGROUND (face) != 0
1185 ? [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)]
1186 : FRAME_BACKGROUND_COLOR (s->f)) set];
1188 [FRAME_CURSOR_COLOR (s->f) set];
1192 /* set up for character rendering */
1193 if (s->hl == DRAW_CURSOR)
1194 col = FRAME_BACKGROUND_COLOR (s->f);
1196 col = (NS_FACE_FOREGROUND (face) != 0
1197 ? [NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (face)]
1198 : FRAME_FOREGROUND_COLOR (s->f));
1200 /* render under GNUstep using DPS */
1202 NSGraphicsContext *context = [NSGraphicsContext currentContext];
1205 DPSmoveto (context, r.origin.x, r.origin.y);
1206 GSShowGlyphs (context, c, len);
1214 ns_font_shape (NSFont *font, NSString *string,
1215 struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len,
1216 enum lgstring_direction dir)
1219 NSUInteger result = 0;
1220 NSTextStorage *textStorage;
1221 NSLayoutManager *layoutManager;
1222 NSTextContainer *textContainer;
1223 NSUInteger stringLength;
1224 NSPoint spaceLocation;
1225 /* numberOfGlyphs can't actually be 0, but this pacifies GCC */
1226 NSUInteger used, numberOfGlyphs = 0;
1228 textStorage = [[NSTextStorage alloc] initWithString:string];
1229 layoutManager = [[NSLayoutManager alloc] init];
1230 textContainer = [[NSTextContainer alloc] init];
1232 /* Append a trailing space to measure baseline position. */
1233 [textStorage appendAttributedString:([[[NSAttributedString alloc]
1234 initWithString:@" "] autorelease])];
1235 [textStorage setFont:font];
1236 [textContainer setLineFragmentPadding:0];
1238 [layoutManager addTextContainer:textContainer];
1239 [textContainer release];
1240 [textStorage addLayoutManager:layoutManager];
1241 [layoutManager release];
1243 if (!(textStorage && layoutManager && textContainer))
1246 stringLength = [string length];
1249 (void) [layoutManager glyphRangeForTextContainer:textContainer];
1251 spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
1253 /* Remove the appended trailing space because otherwise it may
1254 generate a wrong result for a right-to-left text. */
1255 [textStorage beginEditing];
1256 [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
1257 [textStorage endEditing];
1258 (void) [layoutManager glyphRangeForTextContainer:textContainer];
1261 while (i < stringLength)
1264 NSFont *fontInTextStorage =
1265 [textStorage attribute: NSFontAttributeName
1267 longestEffectiveRange: &range
1268 inRange: NSMakeRange (0, stringLength)];
1270 if (!(fontInTextStorage == font
1271 || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
1273 i = NSMaxRange (range);
1275 if (i < stringLength)
1276 /* Make the test `used <= glyph_len' below fail if textStorage
1277 contained some fonts other than the specified one. */
1278 used = glyph_len + 1;
1281 NSRange range = NSMakeRange (0, stringLength);
1283 range = [layoutManager glyphRangeForCharacterRange:range
1284 actualCharacterRange:NULL];
1285 numberOfGlyphs = NSMaxRange (range);
1286 used = numberOfGlyphs;
1287 for (i = 0; i < numberOfGlyphs; i++)
1288 if ([layoutManager notShownAttributeForGlyphAtIndex:i])
1292 if (0 < used && used <= glyph_len)
1294 NSUInteger glyphIndex, prevGlyphIndex;
1295 NSUInteger *permutation;
1296 NSRange compRange, range;
1297 CGFloat totalAdvance;
1300 while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
1304 #define RIGHT_TO_LEFT_P permutation
1306 /* Fill the `comp_range' member of struct mac_glyph_layout, and
1307 setup a permutation for right-to-left text. */
1308 compRange = NSMakeRange (0, 0);
1309 for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
1312 struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
1313 NSUInteger characterIndex =
1314 [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
1316 gl->string_index = characterIndex;
1318 if (characterIndex >= NSMaxRange (compRange))
1320 compRange.location = NSMaxRange (compRange);
1323 NSRange characterRange =
1325 rangeOfComposedCharacterSequenceAtIndex:characterIndex];
1328 NSMaxRange (characterRange) - compRange.location;
1329 [layoutManager glyphRangeForCharacterRange:compRange
1330 actualCharacterRange:&characterRange];
1331 characterIndex = NSMaxRange (characterRange) - 1;
1333 while (characterIndex >= NSMaxRange (compRange));
1335 if (RIGHT_TO_LEFT_P)
1336 for (i = 0; i < range.length; i++)
1337 permutation[range.location + i] = NSMaxRange (range) - i - 1;
1339 range = NSMakeRange (NSMaxRange (range), 0);
1342 gl->comp_range.location = compRange.location;
1343 gl->comp_range.length = compRange.length;
1345 while (++glyphIndex < numberOfGlyphs)
1346 if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
1349 if (RIGHT_TO_LEFT_P)
1350 for (i = 0; i < range.length; i++)
1351 permutation[range.location + i] = NSMaxRange (range) - i - 1;
1353 /* Then fill the remaining members. */
1354 glyphIndex = prevGlyphIndex = 0;
1355 while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
1358 if (!RIGHT_TO_LEFT_P)
1363 NSRect *glyphRects =
1365 rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
1366 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
1367 inTextContainer:textContainer rectCount:&nrects];
1369 totalAdvance = NSMaxX (glyphRects[0]);
1372 for (i = 0; i < used; i++)
1374 struct ns_glyph_layout *gl;
1376 NSUInteger nextGlyphIndex;
1381 if (!RIGHT_TO_LEFT_P)
1382 gl = glyph_layouts + i;
1385 NSUInteger dest = permutation[i];
1387 gl = glyph_layouts + dest;
1390 NSUInteger tmp = gl->string_index;
1392 gl->string_index = glyph_layouts[i].string_index;
1393 glyph_layouts[i].string_index = tmp;
1396 gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex];
1398 location = [layoutManager locationForGlyphAtIndex:glyphIndex];
1399 gl->baseline_delta = spaceLocation.y - location.y;
1401 for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
1404 notShownAttributeForGlyphAtIndex:nextGlyphIndex])
1407 if (!RIGHT_TO_LEFT_P)
1411 if (prevGlyphIndex == 0)
1412 glyphRange = NSMakeRange (0, nextGlyphIndex);
1414 glyphRange = NSMakeRange (glyphIndex,
1415 nextGlyphIndex - glyphIndex);
1418 rectArrayForGlyphRange:glyphRange
1419 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
1420 inTextContainer:textContainer rectCount:&nrects];
1421 maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
1422 gl->advance_delta = location.x - totalAdvance;
1423 gl->advance = maxX - totalAdvance;
1424 totalAdvance = maxX;
1430 if (nextGlyphIndex == numberOfGlyphs)
1431 glyphRange = NSMakeRange (prevGlyphIndex,
1432 numberOfGlyphs - prevGlyphIndex);
1434 glyphRange = NSMakeRange (prevGlyphIndex,
1435 glyphIndex + 1 - prevGlyphIndex);
1438 rectArrayForGlyphRange:glyphRange
1439 withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
1440 inTextContainer:textContainer rectCount:&nrects];
1441 minX = min (NSMinX (glyphRects[0]), totalAdvance);
1442 gl->advance = totalAdvance - minX;
1443 totalAdvance = minX;
1444 gl->advance_delta = location.x - totalAdvance;
1447 prevGlyphIndex = glyphIndex + 1;
1448 glyphIndex = nextGlyphIndex;
1451 if (RIGHT_TO_LEFT_P)
1452 xfree (permutation);
1454 #undef RIGHT_TO_LEFT_P
1458 [textStorage release];
1464 nsfont_shape (Lisp_Object lgstring, Lisp_Object direction)
1466 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
1467 struct nsfont_info *font_info = (struct nsfont_info *) font;
1468 struct ns_glyph_layout *glyph_layouts;
1469 NSFont *nsfont = font_info->nsfont;
1470 ptrdiff_t glyph_len, len, i;
1475 glyph_len = LGSTRING_GLYPH_LEN (lgstring);
1476 for (i = 0; i < glyph_len; ++i)
1478 tem = LGSTRING_GLYPH (lgstring, i);
1486 if (INT_MAX / 2 < len)
1487 memory_full (SIZE_MAX);
1491 mb_buf = alloca (len * sizeof *mb_buf);
1493 for (i = 0; i < len; ++i)
1495 uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
1496 mb_buf[i] = (unichar) c;
1499 NSString *string = [NSString stringWithCharacters: mb_buf
1508 enum lgstring_direction dir = DIR_UNKNOWN;
1510 if (EQ (direction, QL2R))
1512 else if (EQ (direction, QR2L))
1514 glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len);
1515 used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir);
1517 for (i = 0; i < used; i++)
1519 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
1520 struct ns_glyph_layout *gl = glyph_layouts + i;
1522 struct font_metrics metrics;
1526 lglyph = LGLYPH_NEW ();
1527 LGSTRING_SET_GLYPH (lgstring, i, lglyph);
1530 from = gl->comp_range.location;
1531 LGLYPH_SET_FROM (lglyph, from);
1533 to = gl->comp_range.location + gl->comp_range.length;
1534 LGLYPH_SET_TO (lglyph, to - 1);
1536 /* LGLYPH_CHAR is used in `describe-char' for checking whether
1537 the composition is trivial. */
1541 if (mb_buf[gl->string_index] >= 0xD800
1542 && mb_buf[gl->string_index] < 0xDC00)
1543 c = (((mb_buf[gl->string_index] - 0xD800) << 10)
1544 + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000);
1546 c = mb_buf[gl->string_index];
1548 LGLYPH_SET_CHAR (lglyph, c);
1552 unsigned long cc = gl->glyph_id;
1553 LGLYPH_SET_CODE (lglyph, cc);
1556 nsfont_text_extents (font, &gl->glyph_id, 1, &metrics);
1557 LGLYPH_SET_WIDTH (lglyph, metrics.width);
1558 LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
1559 LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
1560 LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
1561 LGLYPH_SET_DESCENT (lglyph, metrics.descent);
1565 return make_fixnum (used);
1569 /* ==========================================================================
1571 Font glyph and metrics caching functions
1573 ========================================================================== */
1576 ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c)
1578 unichar characters[] = { c };
1580 [NSString stringWithCharacters: characters
1582 NSDictionary *attributes =
1583 [NSDictionary dictionaryWithObjectsAndKeys:
1584 info->nsfont, NSFontAttributeName, nil];
1585 NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string
1586 attributes: attributes];
1587 NSTextContainer *text_container = [[NSTextContainer alloc] init];
1588 NSLayoutManager *manager = [[NSLayoutManager alloc] init];
1590 [manager addTextContainer: text_container];
1591 [text_container release]; /* Retained by manager */
1592 [storage addLayoutManager: manager];
1593 [manager release]; /* Retained by storage */
1595 NSFont *font_in_storage = [storage attribute: NSFontAttributeName
1597 effectiveRange: NULL];
1598 NSGlyph glyph = FONT_INVALID_CODE;
1600 if ((font_in_storage == info->nsfont
1601 || [[font_in_storage fontName] isEqualToString: [info->nsfont fontName]]))
1605 glyph = [manager glyphAtIndex: 0];
1607 @catch (NSException *e)
1619 /* Find and cache corresponding glyph codes for unicode values in given
1620 hi-byte block of 256. */
1622 ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1624 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1625 unsigned int i, g, idx;
1626 unsigned int *glyphs;
1629 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1634 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int));
1635 if (!unichars || !(font_info->glyphs[block]))
1638 /* Create a string containing all Unicode characters in this block. */
1639 for (idx = block<<8, i = 0; i < 0x100; idx++, i++)
1640 if (idx < 0xD800 || idx > 0xDFFF)
1643 unichars[i] = 0xFEFF;
1644 unichars[0x100] = 0;
1647 glyphs = font_info->glyphs[block];
1648 for (i = 0; i < 0x100; i++, glyphs++)
1651 NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g);
1661 /* Determine and cache metrics for glyphs in given hi-byte block of
1664 ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block)
1668 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1670 struct font_metrics *metrics;
1673 fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n",
1676 /* not implemented yet (as of startup 0.18), so punt */
1678 numGlyphs = 0x10000;
1681 sfont = [font_info->nsfont screenFont];
1683 font_info->metrics[block] = xzalloc (0x100 * sizeof (struct font_metrics));
1684 if (!(font_info->metrics[block]))
1687 metrics = font_info->metrics[block];
1688 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1691 NSRect r = [sfont boundingRectForGlyph: g];
1693 w = max ([sfont advancementForGlyph: g].width, 2.0);
1694 metrics->width = lrint (w);
1699 metrics->rbearing = lrint (rb);
1700 metrics->lbearing = lrint (lb);
1702 metrics->descent = - NSMaxY (r);
1703 metrics->ascent = - NSMinY (r);
1711 ns_dump_glyphstring (struct glyph_string *s)
1715 fprintf (stderr, ("Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1716 "overlap = %d, bg_filled = %d:"),
1717 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1718 s->row->overlapping_p, s->background_filled_p);
1719 for (i =0; i<s->nchars; i++)
1720 putc (s->first_glyph[i].u.ch, stderr);
1721 putc ('\n', stderr);
1724 static void syms_of_nsfont_for_pdumper (void);
1726 struct font_driver const nsfont_driver =
1728 .type = LISPSYM_INITIALLY (Qns),
1729 .case_sensitive = true,
1730 .get_cache = nsfont_get_cache,
1731 .list = nsfont_list,
1732 .match = nsfont_match,
1733 .list_family = nsfont_list_family,
1734 .open_font = nsfont_open,
1735 .close_font = nsfont_close,
1736 .has_char = nsfont_has_char,
1737 .encode_char = nsfont_encode_char,
1738 .text_extents = nsfont_text_extents,
1739 .shape = nsfont_shape,
1740 .draw = nsfont_draw,
1744 syms_of_nsfont (void)
1746 DEFSYM (Qcondensed, "condensed");
1747 DEFSYM (Qmedium, "medium");
1749 DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
1750 doc: /* Internal map of font registry to Unicode script. */);
1751 Vns_reg_to_script = Qnil;
1753 pdumper_do_now_and_after_load (syms_of_nsfont_for_pdumper);
1755 /* Font slant styles. */
1756 DEFSYM (Qreverse_italic, "reverse-italic");
1757 DEFSYM (Qreverse_oblique, "reverse-oblique");
1758 DEFSYM (Qexpanded, "expanded");
1762 syms_of_nsfont_for_pdumper (void)
1764 register_font_driver (&nsfont_driver, NULL);