diff options
| author | Adrian Robert | 2009-06-08 04:33:56 +0000 |
|---|---|---|
| committer | Adrian Robert | 2009-06-08 04:33:56 +0000 |
| commit | 8840261a51e08534a983a4e66da0dff5a456aaff (patch) | |
| tree | cc31f5a494dc6186894b3eaf2c611aa856dee57a /src | |
| parent | 8f1362ef395554eb52dcd5f441ec050cada0f19f (diff) | |
| download | emacs-8840261a51e08534a983a4e66da0dff5a456aaff.tar.gz emacs-8840261a51e08534a983a4e66da0dff5a456aaff.zip | |
Changes to support :script/:lang/:otf in NS font driver.
* nsfont.m (nsfont_escape_name, nsfont_unescape_name)
(nsfont_get_family, nsfont_char_width): Rename to ns_ prefix to
indicate not part of font driver interface, and change callers.
(ns_get_family): Remove pointless null check.
(nsfont_spec_to_traits, nsfont_fmember_to_entity): Replace with
ns_spec_to_descriptor, ns_descriptor_to_entity.
(nsfont_trait_distance, nsfont_make_fontset_for_font): Remove.
(ns_attribute_value, ns_attribute_fvalue, ns_has_attribute)
(ns_spec_to_descriptor, ns_descriptor_to_entity)
(ns_charset_covers, ns_lang_to_script, ns_otf_to_script)
(ns_get_req_script, ns_accumulate_script_ranges)
(ns_script_to_charset, ns_get_covering_families, ns_findfonts):
New functions.
(nsfont_list, nsfont_match): Use ns_findfonts.
(nsfont_open): Use font descriptor instead of traits.
(nsfont_draw): Handle "automatic" (lookup-table) compositions.
(dump_glyphstring): Rename to ns_dump_glyphstring.
Diffstat (limited to 'src')
| -rw-r--r-- | src/nsfont.m | 920 |
1 files changed, 463 insertions, 457 deletions
diff --git a/src/nsfont.m b/src/nsfont.m index bb9754c8b6e..dde21ccd019 100644 --- a/src/nsfont.m +++ b/src/nsfont.m | |||
| @@ -65,7 +65,7 @@ static void ns_glyph_metrics (struct nsfont_info *font_info, | |||
| 65 | /* Replace spaces w/another character so emacs core font parsing routines | 65 | /* Replace spaces w/another character so emacs core font parsing routines |
| 66 | aren't thrown off. */ | 66 | aren't thrown off. */ |
| 67 | static void | 67 | static void |
| 68 | nsfont_escape_name (char *name) | 68 | ns_escape_name (char *name) |
| 69 | { | 69 | { |
| 70 | int i =0, len =strlen (name); | 70 | int i =0, len =strlen (name); |
| 71 | for ( ; i<len; i++) | 71 | for ( ; i<len; i++) |
| @@ -76,7 +76,7 @@ nsfont_escape_name (char *name) | |||
| 76 | 76 | ||
| 77 | /* Reconstruct spaces in a font family name passed through emacs. */ | 77 | /* Reconstruct spaces in a font family name passed through emacs. */ |
| 78 | static void | 78 | static void |
| 79 | nsfont_unescape_name (char *name) | 79 | ns_unescape_name (char *name) |
| 80 | { | 80 | { |
| 81 | int i =0, len =strlen (name); | 81 | int i =0, len =strlen (name); |
| 82 | for ( ; i<len; i++) | 82 | for ( ; i<len; i++) |
| @@ -87,7 +87,7 @@ nsfont_unescape_name (char *name) | |||
| 87 | 87 | ||
| 88 | /* Extract family name from a font spec. */ | 88 | /* Extract family name from a font spec. */ |
| 89 | static NSString * | 89 | static NSString * |
| 90 | nsfont_get_family (Lisp_Object font_spec) | 90 | ns_get_family (Lisp_Object font_spec) |
| 91 | { | 91 | { |
| 92 | Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX); | 92 | Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX); |
| 93 | if (NILP (tem)) | 93 | if (NILP (tem)) |
| @@ -96,11 +96,9 @@ nsfont_get_family (Lisp_Object font_spec) | |||
| 96 | { | 96 | { |
| 97 | char *tmp = strdup (SDATA (SYMBOL_NAME (tem))); | 97 | char *tmp = strdup (SDATA (SYMBOL_NAME (tem))); |
| 98 | NSString *family; | 98 | NSString *family; |
| 99 | nsfont_unescape_name (tmp); | 99 | ns_unescape_name (tmp); |
| 100 | /* TODO: this seems to be needed only for font names that are | 100 | /* For names hard-coded into emacs, like 'helvetica' for splash. */ |
| 101 | hard-coded into emacs, like 'helvetica' for splash screen */ | 101 | tmp[0] = toupper (tmp[0]); |
| 102 | if (tmp) | ||
| 103 | tmp[0] = toupper (tmp[0]); | ||
| 104 | family = [NSString stringWithUTF8String: tmp]; | 102 | family = [NSString stringWithUTF8String: tmp]; |
| 105 | free (tmp); | 103 | free (tmp); |
| 106 | return family; | 104 | return family; |
| @@ -108,116 +106,429 @@ nsfont_get_family (Lisp_Object font_spec) | |||
| 108 | } | 106 | } |
| 109 | 107 | ||
| 110 | 108 | ||
| 111 | /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH to NSFont traits. */ | 109 | /* Return NSNumber or nil if attr is not set. */ |
| 112 | /* TODO (20080601): The font backend's strategy for handling font | 110 | static NSNumber |
| 113 | styles continues to evolve. When/if this stabilizes, we | 111 | *ns_attribute_value (NSFontDescriptor *fdesc, NSString *trait) |
| 114 | can change the code here to be more sophisticated and accurate. | ||
| 115 | For now, we rely on "normal/plain" style being numeric 100. */ | ||
| 116 | #define STYLE_REF 100 | ||
| 117 | static unsigned int | ||
| 118 | nsfont_spec_to_traits (Lisp_Object font_spec) | ||
| 119 | { | 112 | { |
| 120 | unsigned int traits = 0; | 113 | NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; |
| 121 | int n; | 114 | NSNumber *val = [tdict objectForKey: trait]; |
| 115 | return val; | ||
| 116 | } | ||
| 122 | 117 | ||
| 123 | n = FONT_WEIGHT_NUMERIC (font_spec); | ||
| 124 | if (n != -1) | ||
| 125 | traits |= (n > STYLE_REF) ? NSBoldFontMask | ||
| 126 | : (n < STYLE_REF) ? NSUnboldFontMask : 0; | ||
| 127 | 118 | ||
| 128 | n = FONT_SLANT_NUMERIC (font_spec); | 119 | /* Return 0 if attr not set, else value (which might also be 0). */ |
| 129 | if (n != -1) | 120 | static float |
| 130 | traits |= (n > STYLE_REF) ? NSItalicFontMask | 121 | ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) |
| 131 | : (n < STYLE_REF) ? NSUnitalicFontMask : 0; | 122 | { |
| 123 | NSNumber *val = ns_attribute_value (fdesc, trait); | ||
| 124 | return val == nil ? 0.0 : [val floatValue]; | ||
| 125 | } | ||
| 132 | 126 | ||
| 133 | n = FONT_WIDTH_NUMERIC (font_spec); | ||
| 134 | if (n > -1) | ||
| 135 | traits |= (n > STYLE_REF + 10) ? NSExpandedFontMask | ||
| 136 | : (n < STYLE_REF - 10) ? NSExpandedFontMask : 0; | ||
| 137 | 127 | ||
| 138 | /*fprintf (stderr, " returning traits = %u\n", traits); */ | 128 | /* Return whether font has attribute set to non-standard value. */ |
| 139 | return traits; | 129 | static BOOL |
| 130 | ns_has_attribute (NSFontDescriptor *fdesc, NSString *trait) | ||
| 131 | { | ||
| 132 | float v = ns_attribute_fvalue (fdesc, trait); | ||
| 133 | return v < -0.25 || v > 0.25; | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang | ||
| 138 | to NSFont descriptor. Information under extra only needed for matching. */ | ||
| 139 | #define STYLE_REF 100 | ||
| 140 | static NSFontDescriptor | ||
| 141 | *ns_spec_to_descriptor(Lisp_Object font_spec) | ||
| 142 | { | ||
| 143 | NSFontDescriptor *fdesc; | ||
| 144 | NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; | ||
| 145 | NSMutableDictionary *tdict = [NSMutableDictionary new]; | ||
| 146 | NSString *family = ns_get_family (font_spec); | ||
| 147 | float n; | ||
| 148 | |||
| 149 | /* add each attr in font_spec to fdAttrs.. */ | ||
| 150 | n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); | ||
| 151 | if (n != -1 && n != STYLE_REF) | ||
| 152 | [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0] | ||
| 153 | forKey: NSFontWeightTrait]; | ||
| 154 | n = min (FONT_SLANT_NUMERIC (font_spec), 200); | ||
| 155 | if (n != -1 && n != STYLE_REF) | ||
| 156 | [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0] | ||
| 157 | forKey: NSFontSlantTrait]; | ||
| 158 | n = min (FONT_WIDTH_NUMERIC (font_spec), 200); | ||
| 159 | if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) | ||
| 160 | [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0] | ||
| 161 | forKey: NSFontWidthTrait]; | ||
| 162 | if ([tdict count] > 0) | ||
| 163 | [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; | ||
| 164 | |||
| 165 | fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]; | ||
| 166 | if (family != nil) | ||
| 167 | fdesc = [fdesc fontDescriptorWithFamily: family]; | ||
| 168 | return fdesc; | ||
| 140 | } | 169 | } |
| 141 | 170 | ||
| 142 | 171 | ||
| 143 | /* Converts NSArray of PS name, non-family part, weight, and traits to a | 172 | /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */ |
| 144 | font backend font-entity. */ | ||
| 145 | static Lisp_Object | 173 | static Lisp_Object |
| 146 | nsfont_fmember_to_entity (NSString *family, NSArray *famMember) | 174 | ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style) |
| 147 | { | 175 | { |
| 148 | Lisp_Object font_entity = font_make_entity (); | 176 | Lisp_Object font_entity = font_make_entity (); |
| 149 | unsigned int traits = [[famMember objectAtIndex: 3] unsignedIntValue]; | 177 | /* NSString *psName = [desc postscriptName]; */ |
| 150 | /* NSString *psName = [famMember objectAtIndex: 0]; */ | 178 | NSString *family = [desc objectForKey: NSFontFamilyAttribute]; |
| 151 | NSMutableString *suffix = [[famMember objectAtIndex: 1] mutableCopy]; | 179 | char *escapedFamily = strdup ([family UTF8String]); |
| 152 | char *escapedFamily = strdup ([family UTF8String]); | 180 | unsigned int traits = [desc symbolicTraits]; |
| 153 | 181 | ||
| 154 | nsfont_escape_name (escapedFamily); | 182 | ns_escape_name (escapedFamily); |
| 155 | [suffix replaceOccurrencesOfString: @" " withString: @"" options: 0 | 183 | |
| 156 | range: NSMakeRange (0, [suffix length])]; | 184 | ASET (font_entity, FONT_TYPE_INDEX, Qns); |
| 157 | 185 | ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); | |
| 158 | ASET (font_entity, FONT_TYPE_INDEX, Qns); | 186 | ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); |
| 159 | ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple); | 187 | ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil); |
| 160 | ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily)); | 188 | ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); |
| 161 | ASET (font_entity, FONT_ADSTYLE_INDEX, intern ([suffix UTF8String])); | 189 | |
| 162 | ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1); | 190 | FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, |
| 163 | 191 | traits & NSFontBoldTrait ? Qbold : Qmedium); | |
| 164 | FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, | 192 | /* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, |
| 165 | traits & NSBoldFontMask ? Qbold : Qmedium); | 193 | make_number (100 + 100 |
| 166 | FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, | 194 | * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/ |
| 167 | traits & NSItalicFontMask ? Qitalic : Qnormal); /*XXX: should be Qroman */ | 195 | FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, |
| 168 | FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, | 196 | traits & NSFontItalicTrait ? Qitalic : Qnormal); |
| 169 | traits & NSCondensedFontMask ? Qcondensed : | 197 | /* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, |
| 170 | traits & NSExpandedFontMask ? Qexpanded : Qnormal); | 198 | make_number (100 + 100 |
| 171 | 199 | * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/ | |
| 172 | ASET (font_entity, FONT_SIZE_INDEX, make_number (0)); | 200 | FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, |
| 173 | ASET (font_entity, FONT_EXTRA_INDEX, Qnil); | 201 | traits & NSFontCondensedTrait ? Qcondensed : |
| 174 | ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); | 202 | traits & NSFontExpandedTrait ? Qexpanded : Qnormal); |
| 203 | /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, | ||
| 204 | make_number (100 + 100 | ||
| 205 | * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ | ||
| 206 | |||
| 207 | ASET (font_entity, FONT_SIZE_INDEX, make_number (0)); | ||
| 208 | ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0)); | ||
| 209 | ASET (font_entity, FONT_SPACING_INDEX, | ||
| 210 | make_number([desc symbolicTraits] & NSFontMonoSpaceTrait | ||
| 211 | ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); | ||
| 212 | |||
| 213 | ASET (font_entity, FONT_EXTRA_INDEX, extra); | ||
| 214 | ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); | ||
| 215 | |||
| 216 | if (NSFONT_TRACE) | ||
| 217 | { | ||
| 218 | fprintf (stderr, "created font_entity:\n "); | ||
| 219 | debug_print (font_entity); | ||
| 220 | } | ||
| 175 | 221 | ||
| 176 | if (NSFONT_TRACE) | 222 | free (escapedFamily); |
| 177 | { | 223 | return font_entity; |
| 178 | fprintf (stderr, "created font_entity:\n "); | 224 | } |
| 179 | debug_print (font_entity); | ||
| 180 | } | ||
| 181 | 225 | ||
| 182 | [suffix release]; | 226 | |
| 183 | free (escapedFamily); | 227 | /* Default font entity. */ |
| 184 | return font_entity; | 228 | static Lisp_Object |
| 229 | ns_fallback_entity () | ||
| 230 | { | ||
| 231 | return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] | ||
| 232 | fontDescriptor], Qnil, NULL); | ||
| 185 | } | 233 | } |
| 186 | 234 | ||
| 187 | 235 | ||
| 188 | /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */ | 236 | /* Utility: get width of a char c in screen font sfont */ |
| 189 | static int | 237 | static float |
| 190 | nsfont_trait_distance (unsigned int traits1, unsigned int traits2) | 238 | ns_char_width (NSFont *sfont, int c) |
| 191 | { | 239 | { |
| 192 | int i, d = 0; | 240 | float w; |
| 193 | for (i = 0; i < sizeof (unsigned int) * 8; i++) | 241 | NSString *cstr = [NSString stringWithFormat: @"%c", c]; |
| 194 | { | 242 | #ifdef NS_IMPL_COCOA |
| 195 | d += (traits1 & 0x1) ^ (traits2 & 0x1); | 243 | NSGlyph glyph = [sfont glyphWithName: cstr]; |
| 196 | traits1 >>= 1; | 244 | if (glyph) |
| 197 | traits2 >>= 1; | 245 | { |
| 198 | } | 246 | float w = [sfont advancementForGlyph: glyph].width; |
| 199 | return d; | 247 | if (w >= 1.5) |
| 248 | return w; | ||
| 249 | } | ||
| 250 | #endif | ||
| 251 | w = [sfont widthOfString: cstr]; | ||
| 252 | return max (w, 2.0); | ||
| 253 | } | ||
| 254 | |||
| 255 | |||
| 256 | /* Return whether set1 covers set2 to a reasonable extent given by pct. | ||
| 257 | We check, out of each 16 unicode char range containing chars in set2, | ||
| 258 | whether at least one character is present in set1. | ||
| 259 | This must be true for pct of the pairs to consider it covering. */ | ||
| 260 | static BOOL | ||
| 261 | ns_charset_covers(NSCharacterSet *set1, NSCharacterSet *set2, float pct) | ||
| 262 | { | ||
| 263 | const unsigned short *bytes1 = [[set1 bitmapRepresentation] bytes]; | ||
| 264 | const unsigned short *bytes2 = [[set2 bitmapRepresentation] bytes]; | ||
| 265 | int i, off = 0, tot = 0; | ||
| 266 | |||
| 267 | for (i=0; i<4096; i++, bytes1++, bytes2++) | ||
| 268 | if (*bytes2) | ||
| 269 | { | ||
| 270 | tot++; | ||
| 271 | if (*bytes1 == 0) // *bytes1 & *bytes2 != *bytes2 | ||
| 272 | off++; | ||
| 273 | } | ||
| 274 | //fprintf(stderr, "off = %d\ttot = %d\n", off,tot); | ||
| 275 | return (float)off / tot < 1.0 - pct; | ||
| 276 | } | ||
| 277 | |||
| 278 | |||
| 279 | /* Convert :lang property to a script. Use of :lang property by font backend | ||
| 280 | seems to be limited for now (2009/05) to ja, zh, and ko. */ | ||
| 281 | static NSString | ||
| 282 | *ns_lang_to_script (Lisp_Object lang) | ||
| 283 | { | ||
| 284 | if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ja")) | ||
| 285 | return @"han"; | ||
| 286 | /* NOTE: ja given for any hanzi that's also a kanji, but Chinese fonts | ||
| 287 | have more characters. */ | ||
| 288 | else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "zh")) | ||
| 289 | return @"han"; | ||
| 290 | else if (!strcmp (SDATA (SYMBOL_NAME (lang)), "ko")) | ||
| 291 | return @"hangul"; | ||
| 292 | else | ||
| 293 | return @""; | ||
| 294 | } | ||
| 295 | |||
| 296 | |||
| 297 | /* Convert OTF 4-letter script code to emacs script name. (Why can't | ||
| 298 | everyone just use some standard unicode names for these?) */ | ||
| 299 | static NSString | ||
| 300 | *ns_otf_to_script (Lisp_Object otf) | ||
| 301 | { | ||
| 302 | Lisp_Object script = assq_no_quit (XCAR (otf), Votf_script_alist); | ||
| 303 | return CONSP (script) | ||
| 304 | ? [NSString stringWithUTF8String: SDATA (SYMBOL_NAME XCDR ((script)))] | ||
| 305 | : @""; | ||
| 306 | } | ||
| 307 | |||
| 308 | |||
| 309 | /* Searches the :script, :lang, and :otf extra-bundle properties of the spec | ||
| 310 | for something that can be mapped to a unicode script. Empty string returned | ||
| 311 | if no script spec found. | ||
| 312 | TODO: Eventually registry / encoding should be checked and mapped, but for | ||
| 313 | now the font backend will try script/lang/otf if registry fails, so it is | ||
| 314 | not needed. */ | ||
| 315 | static NSString | ||
| 316 | *ns_get_req_script (Lisp_Object font_spec) | ||
| 317 | { | ||
| 318 | Lisp_Object extra = AREF (font_spec, FONT_EXTRA_INDEX); | ||
| 319 | |||
| 320 | for ( ; CONSP (extra); extra = XCDR (extra)) | ||
| 321 | { | ||
| 322 | Lisp_Object tmp = XCAR (extra); | ||
| 323 | if (CONSP (tmp)) | ||
| 324 | { | ||
| 325 | Lisp_Object key = XCAR (tmp), val = XCDR (tmp); | ||
| 326 | if (EQ (key, QCscript) && SYMBOLP (val)) | ||
| 327 | return [NSString stringWithUTF8String: | ||
| 328 | SDATA (SYMBOL_NAME (val))]; | ||
| 329 | if (EQ (key, QClang) && SYMBOLP (val)) | ||
| 330 | return ns_lang_to_script (val); | ||
| 331 | if (EQ (key, QCotf) && CONSP (val) && SYMBOLP (XCAR (val))) | ||
| 332 | return ns_otf_to_script (val); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | return @""; | ||
| 336 | } | ||
| 337 | |||
| 338 | |||
| 339 | /* This small function is static in fontset.c. If it can be made public for | ||
| 340 | all ports, remove this, but otherwise it doesn't seem worth the ifdefs. */ | ||
| 341 | static void | ||
| 342 | accumulate_script_ranges (Lisp_Object arg, Lisp_Object range, Lisp_Object val) | ||
| 343 | { | ||
| 344 | if (EQ (XCAR (arg), val)) | ||
| 345 | { | ||
| 346 | if (CONSP (range)) | ||
| 347 | XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg))); | ||
| 348 | else | ||
| 349 | XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg))); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | |||
| 354 | /* Use the unicode range information in Vchar_script_table to convert a script | ||
| 355 | name into an NSCharacterSet. */ | ||
| 356 | static NSCharacterSet | ||
| 357 | *ns_script_to_charset (NSString *scriptName) | ||
| 358 | { | ||
| 359 | NSMutableCharacterSet *charset = [NSMutableCharacterSet new]; | ||
| 360 | Lisp_Object script = intern ([scriptName UTF8String]); | ||
| 361 | Lisp_Object script_list = XCHAR_TABLE (Vchar_script_table)->extras[0]; | ||
| 362 | |||
| 363 | if (! NILP (Fmemq (script, script_list))) | ||
| 364 | { | ||
| 365 | Lisp_Object ranges, range_list; | ||
| 366 | |||
| 367 | ranges = Fcons (script, Qnil); | ||
| 368 | map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table, | ||
| 369 | ranges); | ||
| 370 | range_list = Fnreverse (XCDR (ranges)); | ||
| 371 | if (! NILP (range_list)) | ||
| 372 | { | ||
| 373 | for (; CONSP (range_list); range_list = XCDR (range_list)) | ||
| 374 | { | ||
| 375 | int start = XINT (XCAR (XCAR (range_list))); | ||
| 376 | int end = XINT (XCDR (XCAR (range_list))); | ||
| 377 | if (NSFONT_TRACE) | ||
| 378 | debug_print (XCAR (range_list)); | ||
| 379 | if (end < 0x10000) | ||
| 380 | [charset addCharactersInRange: | ||
| 381 | NSMakeRange (start, end-start)]; | ||
| 382 | } | ||
| 383 | } | ||
| 384 | } | ||
| 385 | return charset; | ||
| 200 | } | 386 | } |
| 201 | 387 | ||
| 202 | 388 | ||
| 203 | /* Default font entity based on Monaco. */ | 389 | /* Return an array of font families containing characters for the given |
| 390 | script, for the given coverage criterion, including at least LastResort. | ||
| 391 | Results are cached by script for faster access. | ||
| 392 | If none are found, we reduce the percentage and try again, until 5%. | ||
| 393 | This provides a font with at least some characters if such can be found. | ||
| 394 | We don't use isSupersetOfSet: because (a) it doesn't work on Tiger, and | ||
| 395 | (b) need approximate match as fonts covering full unicode ranges are rare. */ | ||
| 396 | static NSSet | ||
| 397 | *ns_get_covering_families (NSString *script, float pct) | ||
| 398 | { | ||
| 399 | static NSMutableDictionary *scriptToFamilies = nil; | ||
| 400 | NSMutableSet *families; | ||
| 401 | |||
| 402 | if (NSFONT_TRACE) | ||
| 403 | NSLog(@"Request covering families for script: '%@'", script); | ||
| 404 | |||
| 405 | if (scriptToFamilies == nil) | ||
| 406 | scriptToFamilies = [NSMutableDictionary dictionaryWithCapacity: 30]; | ||
| 407 | |||
| 408 | if ((families = [scriptToFamilies objectForKey: script]) == nil) | ||
| 409 | { | ||
| 410 | NSFontManager *fontMgr = [NSFontManager sharedFontManager]; | ||
| 411 | NSArray *allFamilies = [fontMgr availableFontFamilies]; | ||
| 412 | |||
| 413 | if ([script length] == 0) | ||
| 414 | families = [NSMutableSet setWithArray: allFamilies]; | ||
| 415 | else | ||
| 416 | { | ||
| 417 | NSCharacterSet *charset = ns_script_to_charset (script); | ||
| 418 | NSString *family; | ||
| 419 | families = [NSMutableSet setWithCapacity: 10]; | ||
| 420 | while (1) | ||
| 421 | { | ||
| 422 | NSEnumerator *allFamiliesEnum = [allFamilies objectEnumerator]; | ||
| 423 | while (family = [allFamiliesEnum nextObject]) | ||
| 424 | { | ||
| 425 | NSCharacterSet *fset = [[fontMgr fontWithFamily: family | ||
| 426 | traits: 0 weight: 5 size: 12.0] coveredCharacterSet]; | ||
| 427 | /* Some fonts on OS X, maybe many on GNUstep, return nil. */ | ||
| 428 | if (fset == nil) | ||
| 429 | fset = [NSCharacterSet characterSetWithRange: | ||
| 430 | NSMakeRange (0, 127)]; | ||
| 431 | if (ns_charset_covers(fset, charset, pct)) | ||
| 432 | [families addObject: family]; | ||
| 433 | } | ||
| 434 | pct -= 0.2; | ||
| 435 | if ([families count] > 0 || pct < 0.05) | ||
| 436 | break; | ||
| 437 | } | ||
| 438 | } | ||
| 439 | #ifdef NS_IMPL_COCOA | ||
| 440 | if ([families count] == 0) | ||
| 441 | [families addObject: @"LastResort"]; | ||
| 442 | #endif | ||
| 443 | [scriptToFamilies setObject: families forKey: script]; | ||
| 444 | } | ||
| 445 | |||
| 446 | if (NSFONT_TRACE) | ||
| 447 | NSLog(@" returning %d families", [families count]); | ||
| 448 | return families; | ||
| 449 | } | ||
| 450 | |||
| 451 | |||
| 452 | /* Implementation for list() and match(). List() can return nil, match() | ||
| 453 | must return something. Strategy is to drop family name from attribute | ||
| 454 | matching set for match. */ | ||
| 204 | static Lisp_Object | 455 | static Lisp_Object |
| 205 | nsfont_fallback_entity () | 456 | ns_findfonts (Lisp_Object font_spec, BOOL isMatch) |
| 206 | { | 457 | { |
| 207 | NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; | 458 | Lisp_Object tem, list = Qnil; |
| 208 | NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"", | 459 | NSFontDescriptor *fdesc, *desc; |
| 209 | [NSNumber numberWithUnsignedInt: 5], | 460 | NSMutableSet *fkeys; |
| 210 | [NSNumber numberWithUnsignedInt: 0], nil]; | 461 | NSArray *matchingDescs; |
| 211 | return nsfont_fmember_to_entity (family, famMemberSpec); | 462 | NSEnumerator *dEnum; |
| 463 | NSString *family; | ||
| 464 | NSSet *cFamilies; | ||
| 465 | BOOL foundItal = NO; | ||
| 466 | |||
| 467 | if (NSFONT_TRACE) | ||
| 468 | { | ||
| 469 | fprintf (stderr, "nsfont: %s for fontspec:\n ", | ||
| 470 | (isMatch ? "match" : "list")); | ||
| 471 | debug_print (font_spec); | ||
| 472 | } | ||
| 473 | |||
| 474 | /* If has non-unicode registry, give up. */ | ||
| 475 | tem = AREF (font_spec, FONT_REGISTRY_INDEX); | ||
| 476 | if (! NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp)) | ||
| 477 | return isMatch ? ns_fallback_entity () : Qnil; | ||
| 478 | |||
| 479 | cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90); | ||
| 480 | |||
| 481 | fdesc = ns_spec_to_descriptor (font_spec); | ||
| 482 | fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]]; | ||
| 483 | if (isMatch) | ||
| 484 | [fkeys removeObject: NSFontFamilyAttribute]; | ||
| 485 | |||
| 486 | matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys]; | ||
| 487 | if (NSFONT_TRACE) | ||
| 488 | NSLog(@"Got desc %@ and found %d matching fonts from it: ", fdesc, | ||
| 489 | [matchingDescs count]); | ||
| 490 | |||
| 491 | for (dEnum = [matchingDescs objectEnumerator]; desc = [dEnum nextObject]; ) | ||
| 492 | { | ||
| 493 | if (![cFamilies containsObject: | ||
| 494 | [desc objectForKey: NSFontFamilyAttribute]]) | ||
| 495 | continue; | ||
| 496 | list = Fcons (ns_descriptor_to_entity (desc, | ||
| 497 | AREF (font_spec, FONT_EXTRA_INDEX), | ||
| 498 | NULL), list); | ||
| 499 | if (ns_has_attribute (desc, NSFontSlantTrait)) | ||
| 500 | foundItal = YES; | ||
| 501 | } | ||
| 502 | |||
| 503 | /* Add synthItal member if needed. */ | ||
| 504 | family = [fdesc objectForKey: NSFontFamilyAttribute]; | ||
| 505 | if (family != nil && !foundItal && XINT (Flength (list)) > 0 | ||
| 506 | && (ns_attribute_value (fdesc, NSFontSlantTrait) == nil | ||
| 507 | || ns_has_attribute (fdesc, NSFontSlantTrait))) | ||
| 508 | { | ||
| 509 | NSFontDescriptor *sDesc = [[[NSFontDescriptor new] | ||
| 510 | fontDescriptorWithSymbolicTraits: NSFontItalicTrait] | ||
| 511 | fontDescriptorWithFamily: family]; | ||
| 512 | list = Fcons (ns_descriptor_to_entity (sDesc, | ||
| 513 | AREF (font_spec, FONT_EXTRA_INDEX), | ||
| 514 | "synthItal"), list); | ||
| 515 | } | ||
| 516 | |||
| 517 | if (NSFONT_TRACE) | ||
| 518 | fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list))); | ||
| 519 | |||
| 520 | return list; | ||
| 212 | } | 521 | } |
| 213 | 522 | ||
| 214 | 523 | ||
| 524 | |||
| 215 | /* ========================================================================== | 525 | /* ========================================================================== |
| 216 | 526 | ||
| 217 | Font driver implementation | 527 | Font driver implementation |
| 218 | 528 | ||
| 219 | ========================================================================== */ | 529 | ========================================================================== */ |
| 220 | 530 | ||
| 531 | |||
| 221 | static Lisp_Object nsfont_get_cache (FRAME_PTR frame); | 532 | static Lisp_Object nsfont_get_cache (FRAME_PTR frame); |
| 222 | static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec); | 533 | static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec); |
| 223 | static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec); | 534 | static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec); |
| @@ -265,178 +576,33 @@ nsfont_get_cache (FRAME_PTR frame) | |||
| 265 | } | 576 | } |
| 266 | 577 | ||
| 267 | 578 | ||
| 268 | /* List fonts exactly matching with FONT_SPEC on FRAME. The value | 579 | /* List fonts exactly matching with FONT_SPEC on FRAME. The value is a |
| 269 | is a **list** of font-entities. This is the sole API that | 580 | **list** of font-entities. This and match () are sole APIs that allocate |
| 270 | allocates font-entities. */ | 581 | font-entities. Properties to be considered (2009/05/19) are: |
| 582 | regular: foundry, family, adstyle, registry | ||
| 583 | extended: script, lang, otf | ||
| 584 | "Extended" properties are not part of the vector but get stored as | ||
| 585 | lisp properties under FONT_EXTRA_INDEX. | ||
| 586 | |||
| 587 | The returned entities should have type set (to 'ns), plus the following: | ||
| 588 | foundry, family, adstyle, registry, | ||
| 589 | weight, slant, width, size (0 if scalable), | ||
| 590 | dpi, spacing, avgwidth (0 if scalable) */ | ||
| 271 | static Lisp_Object | 591 | static Lisp_Object |
| 272 | nsfont_list (Lisp_Object frame, Lisp_Object font_spec) | 592 | nsfont_list (Lisp_Object frame, Lisp_Object font_spec) |
| 273 | { | 593 | { |
| 274 | Lisp_Object list = Qnil; | 594 | return ns_findfonts (font_spec, NO); |
| 275 | Lisp_Object tem; | ||
| 276 | NSString *family; | ||
| 277 | NSArray *families; | ||
| 278 | NSEnumerator *famEnum; | ||
| 279 | NSFontManager *fontMgr; | ||
| 280 | unsigned int traits = nsfont_spec_to_traits (font_spec); | ||
| 281 | |||
| 282 | if (NSFONT_TRACE) | ||
| 283 | { | ||
| 284 | fprintf (stderr, "nsfont: list for fontspec:\n "); | ||
| 285 | debug_print (font_spec); | ||
| 286 | } | ||
| 287 | |||
| 288 | /* if has non-unicode registry, give up */ | ||
| 289 | tem = AREF (font_spec, FONT_REGISTRY_INDEX); | ||
| 290 | if (!EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp)) | ||
| 291 | return Qnil; | ||
| 292 | |||
| 293 | fontMgr = [NSFontManager sharedFontManager]; | ||
| 294 | |||
| 295 | family = nsfont_get_family (font_spec); | ||
| 296 | |||
| 297 | if (family != nil) | ||
| 298 | families = [NSArray arrayWithObject: family]; | ||
| 299 | else | ||
| 300 | families = [fontMgr availableFontFamilies]; | ||
| 301 | |||
| 302 | for (famEnum = [families objectEnumerator]; family = [famEnum nextObject]; ) | ||
| 303 | { | ||
| 304 | NSEnumerator *fm; | ||
| 305 | NSArray *fmember, *firstMember = nil; | ||
| 306 | unsigned int mtraits; | ||
| 307 | BOOL foundItal = NO || (traits & NSUnitalicFontMask); | ||
| 308 | NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family]; | ||
| 309 | #ifdef NS_IMPL_COCOA | ||
| 310 | /* LastResort is special: not a family but a font name only */ | ||
| 311 | if ([@"LastResort" isEqualToString: family] && [famMembers count] == 0) | ||
| 312 | { | ||
| 313 | famMembers = [NSArray arrayWithObject: [NSArray arrayWithObjects: | ||
| 314 | @"LastResort", @"", [NSNumber numberWithUnsignedInt: 5], | ||
| 315 | [NSNumber numberWithUnsignedInt: 0], nil]]; | ||
| 316 | } | ||
| 317 | #endif | ||
| 318 | |||
| 319 | /* fmember = [postscriptName style weight traits] */ | ||
| 320 | fm = [famMembers objectEnumerator]; | ||
| 321 | while (fmember = [fm nextObject]) | ||
| 322 | { | ||
| 323 | mtraits = [[fmember objectAtIndex: 3] unsignedIntValue]; | ||
| 324 | if ((mtraits & traits) == traits) | ||
| 325 | { | ||
| 326 | list = Fcons (nsfont_fmember_to_entity (family, fmember), list); | ||
| 327 | if (mtraits & NSItalicFontMask) | ||
| 328 | foundItal = YES; | ||
| 329 | if (firstMember == nil) | ||
| 330 | firstMember = fmember; | ||
| 331 | } | ||
| 332 | } | ||
| 333 | if (foundItal == NO && firstMember != nil) | ||
| 334 | { | ||
| 335 | /* no italic member found; add a synthesized one */ | ||
| 336 | NSMutableArray *smember = [firstMember mutableCopy]; | ||
| 337 | [smember replaceObjectAtIndex: 1 withObject: @"synthItal" ]; | ||
| 338 | mtraits = [[fmember objectAtIndex: 3] unsignedIntValue]; | ||
| 339 | mtraits |= NSItalicFontMask; | ||
| 340 | [smember replaceObjectAtIndex: 3 | ||
| 341 | withObject: [NSNumber numberWithUnsignedInt: mtraits]]; | ||
| 342 | /*NSLog (@"-- adding synthItal member: %@", smember); */ | ||
| 343 | list = Fcons (nsfont_fmember_to_entity (family, smember), list); | ||
| 344 | [smember release]; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | if (NSFONT_TRACE) | ||
| 349 | fprintf (stderr, " Returning %d entities.\n", XINT (Flength (list))); | ||
| 350 | |||
| 351 | return list; | ||
| 352 | } | 595 | } |
| 353 | 596 | ||
| 354 | 597 | ||
| 355 | /* Return a font entity most closely maching with FONT_SPEC on | 598 | /* Return a font entity most closely maching with FONT_SPEC on |
| 356 | FRAME. The closeness is determined by the font backend, thus | 599 | FRAME. The closeness is determined by the font backend, thus |
| 357 | `face-font-selection-order' is ignored here. */ | 600 | `face-font-selection-order' is ignored here. |
| 601 | Properties to be considered are same as for list(). */ | ||
| 358 | static Lisp_Object | 602 | static Lisp_Object |
| 359 | nsfont_match (Lisp_Object frame, Lisp_Object font_spec) | 603 | nsfont_match (Lisp_Object frame, Lisp_Object font_spec) |
| 360 | { | 604 | { |
| 361 | long traits = nsfont_spec_to_traits (font_spec); | 605 | return ns_findfonts(font_spec, YES); |
| 362 | NSFontManager *fontMgr = [NSFontManager sharedFontManager]; | ||
| 363 | NSString *family; | ||
| 364 | Lisp_Object tem; | ||
| 365 | |||
| 366 | if (NSFONT_TRACE) | ||
| 367 | { | ||
| 368 | fprintf (stderr, "nsfont: match for fontspec:\n "); | ||
| 369 | debug_print (font_spec); | ||
| 370 | } | ||
| 371 | |||
| 372 | /* if has non-unicode registry, just return fallback */ | ||
| 373 | #if 0 | ||
| 374 | tem = AREF (font_spec, FONT_ADSTYLE_INDEX); | ||
| 375 | if (!NILP (tem)) | ||
| 376 | fprintf (stderr, "adstyle: '%s'\n", SDATA (tem)); | ||
| 377 | #endif | ||
| 378 | tem = AREF (font_spec, FONT_REGISTRY_INDEX); | ||
| 379 | if (!NILP (tem) && !EQ (tem, Qiso10646_1) && !EQ (tem, Qunicode_bmp)) | ||
| 380 | return nsfont_fallback_entity (); | ||
| 381 | |||
| 382 | family = nsfont_get_family (font_spec); | ||
| 383 | |||
| 384 | if (family != nil) | ||
| 385 | { | ||
| 386 | /* try to find close font in family */ | ||
| 387 | NSArray *famMembers = [fontMgr availableMembersOfFontFamily: family]; | ||
| 388 | NSEnumerator *fm = [famMembers objectEnumerator]; | ||
| 389 | NSArray *fmember; | ||
| 390 | int minDist = sizeof (unsigned int) * 8 + 1; | ||
| 391 | int bestMatchIdx = -1; | ||
| 392 | int i; | ||
| 393 | |||
| 394 | for (i =0; fmember = [fm nextObject]; i++) | ||
| 395 | { | ||
| 396 | unsigned int mtraits = [[fmember objectAtIndex: 3] unsignedIntValue]; | ||
| 397 | int dist = nsfont_trait_distance ((mtraits & traits), traits); | ||
| 398 | if (dist < minDist) | ||
| 399 | { | ||
| 400 | bestMatchIdx = i; | ||
| 401 | minDist = dist; | ||
| 402 | } | ||
| 403 | } | ||
| 404 | if (bestMatchIdx != -1) | ||
| 405 | return nsfont_fmember_to_entity | ||
| 406 | (family, [famMembers objectAtIndex: bestMatchIdx]); | ||
| 407 | } | ||
| 408 | |||
| 409 | /* no family that had members was given; find any font matching traits */ | ||
| 410 | { | ||
| 411 | NSArray *fontNames = [fontMgr availableFontNamesWithTraits: traits]; | ||
| 412 | if (fontNames && [fontNames count] > 0) | ||
| 413 | { | ||
| 414 | NSString *fontName = [fontNames objectAtIndex: 0]; | ||
| 415 | /* XXX: is there a more efficient way to get family name? */ | ||
| 416 | NSFont *font = [NSFont fontWithName: fontName size: 0]; | ||
| 417 | if (font != nil) | ||
| 418 | { | ||
| 419 | /* now need to get suffix part of name.. */ | ||
| 420 | NSString *family = [font familyName]; | ||
| 421 | NSEnumerator *fm = [[fontMgr availableMembersOfFontFamily: family] | ||
| 422 | objectEnumerator]; | ||
| 423 | NSArray *fmember; | ||
| 424 | while (fmember = [fm nextObject]) | ||
| 425 | { | ||
| 426 | unsigned int mtraits = | ||
| 427 | [[fmember objectAtIndex: 3] unsignedIntValue]; | ||
| 428 | if (mtraits & traits == traits) | ||
| 429 | return nsfont_fmember_to_entity (family, fmember); | ||
| 430 | } | ||
| 431 | } | ||
| 432 | } | ||
| 433 | } | ||
| 434 | |||
| 435 | /* if we get here, return the fallback */ | ||
| 436 | if (NSFONT_TRACE) | ||
| 437 | fprintf (stderr, " *** returning fallback\n"); | ||
| 438 | |||
| 439 | return nsfont_fallback_entity (); | ||
| 440 | } | 606 | } |
| 441 | 607 | ||
| 442 | 608 | ||
| @@ -462,35 +628,16 @@ nsfont_list_family (Lisp_Object frame) | |||
| 462 | } | 628 | } |
| 463 | 629 | ||
| 464 | 630 | ||
| 465 | /* utility: get width of a char c in screen font sfont */ | ||
| 466 | static float | ||
| 467 | nsfont_char_width (NSFont *sfont, int c) | ||
| 468 | { | ||
| 469 | float w; | ||
| 470 | NSString *cstr = [NSString stringWithFormat: @"%c", c]; | ||
| 471 | #ifdef NS_IMPL_COCOA | ||
| 472 | NSGlyph glyph = [sfont glyphWithName: cstr]; | ||
| 473 | if (glyph) | ||
| 474 | { | ||
| 475 | float w = [sfont advancementForGlyph: glyph].width; | ||
| 476 | if (w >= 1.5) | ||
| 477 | return w; | ||
| 478 | } | ||
| 479 | #endif | ||
| 480 | w = [sfont widthOfString: cstr]; | ||
| 481 | return max (w, 2.0); | ||
| 482 | } | ||
| 483 | |||
| 484 | |||
| 485 | /* Open a font specified by FONT_ENTITY on frame F. If the font is | 631 | /* Open a font specified by FONT_ENTITY on frame F. If the font is |
| 486 | scalable, open it with PIXEL_SIZE. */ | 632 | scalable, open it with PIXEL_SIZE. */ |
| 487 | static Lisp_Object | 633 | static Lisp_Object |
| 488 | nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | 634 | nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) |
| 489 | { | 635 | { |
| 490 | BOOL synthItal; | 636 | BOOL synthItal; |
| 637 | unsigned int traits = 0; | ||
| 491 | struct nsfont_info *font_info; | 638 | struct nsfont_info *font_info; |
| 492 | struct font *font; | 639 | struct font *font; |
| 493 | unsigned int traits = nsfont_spec_to_traits (font_entity); | 640 | NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity); |
| 494 | NSFontManager *fontMgr = [NSFontManager sharedFontManager]; | 641 | NSFontManager *fontMgr = [NSFontManager sharedFontManager]; |
| 495 | NSString *family; | 642 | NSString *family; |
| 496 | NSFont *nsfont, *sfont; | 643 | NSFont *nsfont, *sfont; |
| @@ -506,8 +653,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 506 | entities, due to small differences in numeric values or other issues, | 653 | entities, due to small differences in numeric values or other issues, |
| 507 | or for different copies of the same entity. Therefore we cache to | 654 | or for different copies of the same entity. Therefore we cache to |
| 508 | avoid creating multiple struct font objects (with metrics cache, etc.) | 655 | avoid creating multiple struct font objects (with metrics cache, etc.) |
| 509 | for the same NSFont object. | 656 | for the same NSFont object. */ |
| 510 | 2008/06/01: This is still an issue after font backend refactoring. */ | ||
| 511 | if (fontCache == nil) | 657 | if (fontCache == nil) |
| 512 | fontCache = [[NSMutableDictionary alloc] init]; | 658 | fontCache = [[NSMutableDictionary alloc] init]; |
| 513 | 659 | ||
| @@ -527,21 +673,19 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 527 | tem = AREF (font_entity, FONT_ADSTYLE_INDEX); | 673 | tem = AREF (font_entity, FONT_ADSTYLE_INDEX); |
| 528 | synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)), | 674 | synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)), |
| 529 | 9); | 675 | 9); |
| 530 | family = nsfont_get_family (font_entity); | 676 | family = ns_get_family (font_entity); |
| 531 | if (NSFONT_TRACE) | 677 | if (ns_has_attribute (fontDesc, NSFontWeightTrait)) |
| 532 | { | 678 | traits |= NSBoldFontMask; |
| 533 | fprintf (stderr, "family: '%s'\ttraits = %ld\tbold = %d\titalic = %d\n", | 679 | if (ns_has_attribute (fontDesc, NSFontSlantTrait)) |
| 534 | [family UTF8String], traits, traits & NSBoldFontMask, | 680 | traits |= NSItalicFontMask; |
| 535 | traits & NSItalicFontMask); | ||
| 536 | } | ||
| 537 | 681 | ||
| 538 | /* see http://cocoadev.com/forums/comments.php?DiscussionID =74 */ | 682 | /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */ |
| 539 | fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; | 683 | fixLeopardBug = traits & NSBoldFontMask ? 10 : 5; |
| 540 | nsfont = [fontMgr fontWithFamily: family | 684 | nsfont = [fontMgr fontWithFamily: family |
| 541 | traits: traits weight: fixLeopardBug | 685 | traits: traits weight: fixLeopardBug |
| 542 | size: pixel_size]; | 686 | size: pixel_size]; |
| 543 | /* if didn't find, try synthetic italic */ | 687 | /* if didn't find, try synthetic italic */ |
| 544 | if (nsfont == nil && synthItal && (traits & NSItalicFontMask)) | 688 | if (nsfont == nil && synthItal) |
| 545 | { | 689 | { |
| 546 | nsfont = [fontMgr fontWithFamily: family | 690 | nsfont = [fontMgr fontWithFamily: family |
| 547 | traits: traits & ~NSItalicFontMask | 691 | traits: traits & ~NSItalicFontMask |
| @@ -550,9 +694,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 550 | #ifdef NS_IMPL_COCOA | 694 | #ifdef NS_IMPL_COCOA |
| 551 | /* LastResort not really a family */ | 695 | /* LastResort not really a family */ |
| 552 | if (nsfont == nil && [@"LastResort" isEqualToString: family]) | 696 | if (nsfont == nil && [@"LastResort" isEqualToString: family]) |
| 553 | { | ||
| 554 | nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size]; | 697 | nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size]; |
| 555 | } | ||
| 556 | #endif | 698 | #endif |
| 557 | 699 | ||
| 558 | if (nsfont == nil) | 700 | if (nsfont == nil) |
| @@ -560,11 +702,6 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 560 | message_with_string ("*** Warning: font in family '%s' not found", | 702 | message_with_string ("*** Warning: font in family '%s' not found", |
| 561 | build_string ([family UTF8String]), 1); | 703 | build_string ([family UTF8String]), 1); |
| 562 | nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; | 704 | nsfont = [NSFont userFixedPitchFontOfSize: pixel_size]; |
| 563 | if (!nsfont) | ||
| 564 | { | ||
| 565 | fprintf (stderr, "*** Emacs.app: unable to load backup font\n"); | ||
| 566 | return Qnil; | ||
| 567 | } | ||
| 568 | } | 705 | } |
| 569 | 706 | ||
| 570 | if (NSFONT_TRACE) | 707 | if (NSFONT_TRACE) |
| @@ -576,7 +713,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 576 | { | 713 | { |
| 577 | if (NSFONT_TRACE) | 714 | if (NSFONT_TRACE) |
| 578 | fprintf(stderr, "*** nsfont_open CACHE HIT!\n"); | 715 | fprintf(stderr, "*** nsfont_open CACHE HIT!\n"); |
| 579 | // FIXME: Cast from (unsigned long) to Lisp_Object. | 716 | /* FIXME: Cast from (unsigned long) to Lisp_Object. */ |
| 580 | XHASH (font_object) = [cached unsignedLongValue]; | 717 | XHASH (font_object) = [cached unsignedLongValue]; |
| 581 | return font_object; | 718 | return font_object; |
| 582 | } | 719 | } |
| @@ -585,14 +722,13 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 585 | font_object = font_make_object (VECSIZE (struct nsfont_info), | 722 | font_object = font_make_object (VECSIZE (struct nsfont_info), |
| 586 | font_entity, pixel_size); | 723 | font_entity, pixel_size); |
| 587 | if (!synthItal) | 724 | if (!synthItal) |
| 588 | [fontCache | 725 | [fontCache setObject: [NSNumber numberWithUnsignedLong: |
| 589 | setObject: [NSNumber numberWithUnsignedLong: | 726 | (unsigned long) XHASH (font_object)] |
| 590 | (unsigned long) XHASH (font_object)] | 727 | forKey: nsfont]; |
| 591 | forKey: nsfont]; | ||
| 592 | } | 728 | } |
| 593 | 729 | ||
| 594 | font_info = (struct nsfont_info *) XFONT_OBJECT (font_object); | 730 | font_info = (struct nsfont_info *) XFONT_OBJECT (font_object); |
| 595 | font = (struct font *)font_info; | 731 | font = (struct font *) font_info; |
| 596 | if (!font) | 732 | if (!font) |
| 597 | return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */ | 733 | return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */ |
| 598 | 734 | ||
| @@ -625,7 +761,6 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 625 | font->relative_compose = 0; | 761 | font->relative_compose = 0; |
| 626 | font->font_encoder = NULL; | 762 | font->font_encoder = NULL; |
| 627 | 763 | ||
| 628 | /* TODO: does anything care about this? */ | ||
| 629 | font->props[FONT_FORMAT_INDEX] = Qns; | 764 | font->props[FONT_FORMAT_INDEX] = Qns; |
| 630 | font->props[FONT_FILE_INDEX] = Qnil; | 765 | font->props[FONT_FILE_INDEX] = Qnil; |
| 631 | 766 | ||
| @@ -643,8 +778,8 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 643 | [font_info->nsfont retain]; | 778 | [font_info->nsfont retain]; |
| 644 | 779 | ||
| 645 | /* set up ns_font (defined in nsgui.h) */ | 780 | /* set up ns_font (defined in nsgui.h) */ |
| 646 | font_info->name = (char *)xmalloc (strlen (fontName)+1); | 781 | font_info->name = (char *)xmalloc (strlen (fontName) + 1); |
| 647 | bcopy (fontName, font_info->name, strlen (fontName)+1); | 782 | bcopy (fontName, font_info->name, strlen (fontName) + 1); |
| 648 | font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; | 783 | font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask; |
| 649 | font_info->ital = | 784 | font_info->ital = |
| 650 | synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); | 785 | synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask); |
| @@ -652,7 +787,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 652 | /* Metrics etc.; some fonts return an unusually large max advance, so we | 787 | /* Metrics etc.; some fonts return an unusually large max advance, so we |
| 653 | only use it for fonts that have wide characters. */ | 788 | only use it for fonts that have wide characters. */ |
| 654 | font_info->width = ([sfont numberOfGlyphs] > 2000) ? | 789 | font_info->width = ([sfont numberOfGlyphs] > 2000) ? |
| 655 | [sfont maximumAdvancement].width : nsfont_char_width (sfont, '0'); | 790 | [sfont maximumAdvancement].width : ns_char_width (sfont, '0'); |
| 656 | 791 | ||
| 657 | brect = [sfont boundingRectForFont]; | 792 | brect = [sfont boundingRectForFont]; |
| 658 | full_height = brect.size.height; | 793 | full_height = brect.size.height; |
| @@ -710,7 +845,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) | |||
| 710 | font->ascent = [sfont ascender]; | 845 | font->ascent = [sfont ascender]; |
| 711 | font->descent = -[sfont descender]; | 846 | font->descent = -[sfont descender]; |
| 712 | font->min_width = [sfont widthOfString: @"|"]; /* FIXME */ | 847 | font->min_width = [sfont widthOfString: @"|"]; /* FIXME */ |
| 713 | font->space_width = lrint (nsfont_char_width (sfont, ' ')); | 848 | font->space_width = lrint (ns_char_width (sfont, ' ')); |
| 714 | font->average_width = lrint (font_info->width); | 849 | font->average_width = lrint (font_info->width); |
| 715 | font->max_width = lrint (font_info->max_bounds.width); | 850 | font->max_width = lrint (font_info->max_bounds.width); |
| 716 | font->height = lrint (font_info->height); | 851 | font->height = lrint (font_info->height); |
| @@ -735,8 +870,7 @@ nsfont_close (FRAME_PTR f, struct font *font) | |||
| 735 | int i; | 870 | int i; |
| 736 | 871 | ||
| 737 | /* FIXME: this occurs apparently due to same failure to detect same font | 872 | /* FIXME: this occurs apparently due to same failure to detect same font |
| 738 | that causes need for cache in nsfont_open () | 873 | that causes need for cache in nsfont_open () */ |
| 739 | (came after unicode-2 -> trunk) */ | ||
| 740 | if (!font_info) | 874 | if (!font_info) |
| 741 | return; | 875 | return; |
| 742 | 876 | ||
| @@ -749,10 +883,10 @@ nsfont_close (FRAME_PTR f, struct font *font) | |||
| 749 | } | 883 | } |
| 750 | [font_info->nsfont release]; | 884 | [font_info->nsfont release]; |
| 751 | #ifdef NS_IMPL_COCOA | 885 | #ifdef NS_IMPL_COCOA |
| 752 | CGFontRelease (font_info->cgfont); | 886 | CGFontRelease (font_info->cgfont); |
| 753 | #endif | 887 | #endif |
| 754 | xfree (font_info->name); | 888 | xfree (font_info->name); |
| 755 | xfree (font_info); | 889 | xfree (font_info); |
| 756 | } | 890 | } |
| 757 | 891 | ||
| 758 | 892 | ||
| @@ -783,7 +917,6 @@ nsfont_encode_char (struct font *font, int c) | |||
| 783 | ns_uni_to_glyphs (font_info, high); | 917 | ns_uni_to_glyphs (font_info, high); |
| 784 | 918 | ||
| 785 | g = font_info->glyphs[high][low]; | 919 | g = font_info->glyphs[high][low]; |
| 786 | /*fprintf (stderr, "mapping char %d -> %d\n", c, g); */ | ||
| 787 | return g == 0xFFFF ? FONT_INVALID_CODE : g; | 920 | return g == 0xFFFF ? FONT_INVALID_CODE : g; |
| 788 | } | 921 | } |
| 789 | 922 | ||
| @@ -857,6 +990,8 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, | |||
| 857 | NSColor *col, *bgCol; | 990 | NSColor *col, *bgCol; |
| 858 | unsigned short *t = s->char2b; | 991 | unsigned short *t = s->char2b; |
| 859 | int i, len; | 992 | int i, len; |
| 993 | char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; | ||
| 994 | int end = isComposite ? s->cmp_to : s->nchars; | ||
| 860 | 995 | ||
| 861 | /* Select face based on input flags */ | 996 | /* Select face based on input flags */ |
| 862 | switch (ns_tmp_flags) | 997 | switch (ns_tmp_flags) |
| @@ -888,16 +1023,32 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, | |||
| 888 | XCharStruct *cs; | 1023 | XCharStruct *cs; |
| 889 | int cwidth, twidth = 0; | 1024 | int cwidth, twidth = 0; |
| 890 | int hi, lo; | 1025 | int hi, lo; |
| 891 | char isComposite = s->first_glyph->type == COMPOSITE_GLYPH; | ||
| 892 | /* FIXME: composition: no vertical displacement is considered. */ | 1026 | /* FIXME: composition: no vertical displacement is considered. */ |
| 893 | t += s->cmp_from; /* advance into composition */ | 1027 | t += s->cmp_from; /* advance into composition */ |
| 894 | for (i = s->cmp_from; i < s->nchars; i++, t++) | 1028 | for (i = s->cmp_from; i < end; i++, t++) |
| 895 | { | 1029 | { |
| 896 | hi = (*t & 0xFF00) >> 8; | 1030 | hi = (*t & 0xFF00) >> 8; |
| 897 | lo = *t & 0x00FF; | 1031 | lo = *t & 0x00FF; |
| 898 | if (isComposite) | 1032 | if (isComposite) |
| 899 | { | 1033 | { |
| 900 | cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth; | 1034 | if (!s->first_glyph->u.cmp.automatic) |
| 1035 | cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth; | ||
| 1036 | else | ||
| 1037 | { | ||
| 1038 | Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); | ||
| 1039 | Lisp_Object glyph = LGSTRING_GLYPH (gstring, i); | ||
| 1040 | if (NILP (LGLYPH_ADJUSTMENT (glyph))) | ||
| 1041 | cwidth = LGLYPH_WIDTH (glyph); | ||
| 1042 | else | ||
| 1043 | { | ||
| 1044 | cwidth = LGLYPH_WADJUST (glyph); | ||
| 1045 | #ifdef NS_IMPL_GNUSTEP | ||
| 1046 | *(adv-1) += LGLYPH_XOFF (glyph); | ||
| 1047 | #else | ||
| 1048 | (*(adv-1)).width += LGLYPH_XOFF (glyph); | ||
| 1049 | #endif | ||
| 1050 | } | ||
| 1051 | } | ||
| 901 | } | 1052 | } |
| 902 | else | 1053 | else |
| 903 | { | 1054 | { |
| @@ -919,7 +1070,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, | |||
| 919 | } | 1070 | } |
| 920 | 1071 | ||
| 921 | /* fill background if requested */ | 1072 | /* fill background if requested */ |
| 922 | if (with_background) | 1073 | if (with_background && !isComposite) |
| 923 | { | 1074 | { |
| 924 | NSRect br = r; | 1075 | NSRect br = r; |
| 925 | int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); | 1076 | int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f); |
| @@ -1098,151 +1249,6 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, | |||
| 1098 | } | 1249 | } |
| 1099 | 1250 | ||
| 1100 | 1251 | ||
| 1101 | /* Auto-creates a fontset built around the font in font_object, | ||
| 1102 | by creating an attributed string with characters from each | ||
| 1103 | script, then requesting the NS text system to fix attributes | ||
| 1104 | in range. */ | ||
| 1105 | void nsfont_make_fontset_for_font (Lisp_Object name, Lisp_Object font_object) | ||
| 1106 | { | ||
| 1107 | Lisp_Object script, famAndReg; | ||
| 1108 | struct nsfont_info *font_info = | ||
| 1109 | (struct nsfont_info *)XFONT_OBJECT (font_object); | ||
| 1110 | |||
| 1111 | /* NS text system (and char buf) init */ | ||
| 1112 | static NSTextStorage *store; | ||
| 1113 | static NSLayoutManager *layout; | ||
| 1114 | static NSRange range; | ||
| 1115 | static NSMutableDictionary *attribs; | ||
| 1116 | static Lisp_Object *scripts; | ||
| 1117 | static int nscripts; | ||
| 1118 | static int *scriptsNchars; | ||
| 1119 | static BOOL firstTime = YES; | ||
| 1120 | Lisp_Object regString = build_string ("iso10646-1"); | ||
| 1121 | int i, j; | ||
| 1122 | |||
| 1123 | if (firstTime == YES) | ||
| 1124 | { | ||
| 1125 | nscripts = XINT (Flength (Vscript_representative_chars)); | ||
| 1126 | scriptsNchars = (int *) malloc (nscripts * sizeof (int)); | ||
| 1127 | unsigned char *buf = malloc (4*nscripts*sizeof (char)); | ||
| 1128 | Lisp_Object scriptsChars = Vscript_representative_chars; | ||
| 1129 | unsigned char *tpos = buf; | ||
| 1130 | |||
| 1131 | scripts = (Lisp_Object *) malloc (nscripts * sizeof (Lisp_Object)); | ||
| 1132 | |||
| 1133 | for (i =0; i<nscripts; i++) | ||
| 1134 | { | ||
| 1135 | Lisp_Object sChars = XCAR (scriptsChars); | ||
| 1136 | Lisp_Object chars = XCDR (sChars); | ||
| 1137 | unsigned int ch, c =0; | ||
| 1138 | scripts[i] = XCAR (sChars); | ||
| 1139 | |||
| 1140 | while (CONSP (chars)) | ||
| 1141 | { | ||
| 1142 | ch = XUINT (XCAR (chars)); | ||
| 1143 | chars = XCDR (chars); | ||
| 1144 | CHAR_STRING_ADVANCE (ch, tpos); | ||
| 1145 | c++; | ||
| 1146 | } | ||
| 1147 | scriptsNchars[i] = c; | ||
| 1148 | |||
| 1149 | scriptsChars = XCDR (scriptsChars); | ||
| 1150 | } | ||
| 1151 | *tpos = '\0'; | ||
| 1152 | |||
| 1153 | store = [[NSTextStorage alloc] init]; | ||
| 1154 | layout = [[NSLayoutManager alloc] init]; | ||
| 1155 | [store addLayoutManager: layout]; | ||
| 1156 | [layout release]; | ||
| 1157 | |||
| 1158 | [store beginEditing]; | ||
| 1159 | [[store mutableString] appendString: | ||
| 1160 | [NSString stringWithUTF8String: buf]]; | ||
| 1161 | [store endEditing]; | ||
| 1162 | |||
| 1163 | free (buf); | ||
| 1164 | range = NSMakeRange (0, [store length]); | ||
| 1165 | |||
| 1166 | attribs = [[NSMutableDictionary alloc] init]; | ||
| 1167 | firstTime = NO; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | /* set the fonts */ | ||
| 1171 | [store beginEditing]; | ||
| 1172 | [store removeAttribute: NSFontAttributeName range: range]; | ||
| 1173 | [attribs setObject: font_info->nsfont forKey: NSFontAttributeName]; | ||
| 1174 | [store addAttributes: attribs range: range]; | ||
| 1175 | [store endEditing]; | ||
| 1176 | |||
| 1177 | /* read them out */ | ||
| 1178 | { | ||
| 1179 | NSMutableDictionary *map = | ||
| 1180 | [NSMutableDictionary dictionaryWithCapacity: nscripts * 4]; | ||
| 1181 | NSEnumerator *fonts; | ||
| 1182 | NSFont *cfont = nil, *tfont; | ||
| 1183 | NSNumber *n; | ||
| 1184 | int idx = 0; | ||
| 1185 | int max; | ||
| 1186 | for (i =0; i<nscripts; i++) | ||
| 1187 | { | ||
| 1188 | [map removeAllObjects]; | ||
| 1189 | for (j =0; j<scriptsNchars[i]; j++) | ||
| 1190 | { | ||
| 1191 | cfont = [store attribute: NSFontAttributeName atIndex: idx++ | ||
| 1192 | effectiveRange: NULL]; | ||
| 1193 | n = [map objectForKey: cfont]; | ||
| 1194 | if (n == nil) | ||
| 1195 | n = [NSNumber numberWithInt: 1]; | ||
| 1196 | else | ||
| 1197 | n = [NSNumber numberWithInt: [n intValue] + 1]; | ||
| 1198 | [map setObject: n forKey: cfont]; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | /* majority rules */ | ||
| 1202 | max = 0; | ||
| 1203 | fonts = [map keyEnumerator]; | ||
| 1204 | while (tfont = [fonts nextObject]) | ||
| 1205 | { | ||
| 1206 | n = [map objectForKey: tfont]; | ||
| 1207 | if ([n intValue] > max) | ||
| 1208 | { | ||
| 1209 | cfont = tfont; | ||
| 1210 | max = [n intValue]; | ||
| 1211 | } | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | if (cfont != nil) | ||
| 1215 | { | ||
| 1216 | char *family = strdup([[cfont familyName] UTF8String]); | ||
| 1217 | Lisp_Object famAndReg; | ||
| 1218 | |||
| 1219 | nsfont_escape_name (family); | ||
| 1220 | famAndReg = Fcons (build_string (family), regString); | ||
| 1221 | |||
| 1222 | if (NSFONT_TRACE) | ||
| 1223 | fprintf (stderr, "%s fontset: use '%s' for script '%s'\n", | ||
| 1224 | font_info->name, family, | ||
| 1225 | SDATA (SYMBOL_NAME (scripts[i]))); | ||
| 1226 | |||
| 1227 | /* TODO: Some of the "scripts" in script-representative-chars are | ||
| 1228 | actually only "sub-scripts" which are not fully defined. For | ||
| 1229 | these, calling set_fontset_font generates an abort. Try to | ||
| 1230 | guess which ones these are and avoid it. */ | ||
| 1231 | if (strstr (SDATA (SYMBOL_NAME (scripts[i])), "mathematical-") | ||
| 1232 | != (char *)SDATA (SYMBOL_NAME (scripts[i]))) | ||
| 1233 | Fset_fontset_font (name, scripts[i], famAndReg, Qnil, Qnil); | ||
| 1234 | free (family); | ||
| 1235 | } | ||
| 1236 | else | ||
| 1237 | { | ||
| 1238 | fprintf (stderr, "%s fontset: none found for script '%s'\n", | ||
| 1239 | font_info->name, SDATA (SYMBOL_NAME (scripts[i]))); | ||
| 1240 | } | ||
| 1241 | } /* for i = script */ | ||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | |||
| 1246 | 1252 | ||
| 1247 | /* ========================================================================== | 1253 | /* ========================================================================== |
| 1248 | 1254 | ||
| @@ -1462,11 +1468,12 @@ ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block) | |||
| 1462 | 1468 | ||
| 1463 | /* Debugging */ | 1469 | /* Debugging */ |
| 1464 | void | 1470 | void |
| 1465 | dump_glyphstring (struct glyph_string *s) | 1471 | ns_dump_glyphstring (struct glyph_string *s) |
| 1466 | { | 1472 | { |
| 1467 | int i; | 1473 | int i; |
| 1468 | 1474 | ||
| 1469 | fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d), overlap = %d, bg_filled = %d:", | 1475 | fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d)," |
| 1476 | "overlap = %d, bg_filled = %d:", | ||
| 1470 | s->nchars, s->x, s->y, s->left_overhang, s->right_overhang, | 1477 | s->nchars, s->x, s->y, s->left_overhang, s->right_overhang, |
| 1471 | s->row->overlapping_p, s->background_filled_p); | 1478 | s->row->overlapping_p, s->background_filled_p); |
| 1472 | for (i =0; i<s->nchars; i++) | 1479 | for (i =0; i<s->nchars; i++) |
| @@ -1475,7 +1482,6 @@ dump_glyphstring (struct glyph_string *s) | |||
| 1475 | } | 1482 | } |
| 1476 | 1483 | ||
| 1477 | 1484 | ||
| 1478 | |||
| 1479 | void | 1485 | void |
| 1480 | syms_of_nsfont () | 1486 | syms_of_nsfont () |
| 1481 | { | 1487 | { |