Mercurial > emacs
comparison src/nsfont.m @ 103343:83dbc377f674
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.
author | Adrian Robert <Adrian.B.Robert@gmail.com> |
---|---|
date | Mon, 08 Jun 2009 04:33:56 +0000 |
parents | c878fe60e8be |
children | 591af7ba061b |
comparison
equal
deleted
inserted
replaced
103342:3565aebd001c | 103343:83dbc377f674 |
---|---|
63 | 63 |
64 | 64 |
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++) |
72 if (name[i] == ' ') | 72 if (name[i] == ' ') |
73 name[i] = '_'; | 73 name[i] = '_'; |
74 } | 74 } |
75 | 75 |
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++) |
83 if (name[i] == '_') | 83 if (name[i] == '_') |
84 name[i] = ' '; | 84 name[i] = ' '; |
85 } | 85 } |
86 | 86 |
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)) |
94 return nil; | 94 return nil; |
95 else | 95 else |
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; |
107 } | 105 } |
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. | 112 { |
115 For now, we rely on "normal/plain" style being numeric 100. */ | 113 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute]; |
114 NSNumber *val = [tdict objectForKey: trait]; | |
115 return val; | |
116 } | |
117 | |
118 | |
119 /* Return 0 if attr not set, else value (which might also be 0). */ | |
120 static float | |
121 ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait) | |
122 { | |
123 NSNumber *val = ns_attribute_value (fdesc, trait); | |
124 return val == nil ? 0.0 : [val floatValue]; | |
125 } | |
126 | |
127 | |
128 /* Return whether font has attribute set to non-standard value. */ | |
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. */ | |
116 #define STYLE_REF 100 | 139 #define STYLE_REF 100 |
117 static unsigned int | 140 static NSFontDescriptor |
118 nsfont_spec_to_traits (Lisp_Object font_spec) | 141 *ns_spec_to_descriptor(Lisp_Object font_spec) |
119 { | 142 { |
120 unsigned int traits = 0; | 143 NSFontDescriptor *fdesc; |
121 int n; | 144 NSMutableDictionary *fdAttrs = [NSMutableDictionary new]; |
122 | 145 NSMutableDictionary *tdict = [NSMutableDictionary new]; |
123 n = FONT_WEIGHT_NUMERIC (font_spec); | 146 NSString *family = ns_get_family (font_spec); |
124 if (n != -1) | 147 float n; |
125 traits |= (n > STYLE_REF) ? NSBoldFontMask | 148 |
126 : (n < STYLE_REF) ? NSUnboldFontMask : 0; | 149 /* add each attr in font_spec to fdAttrs.. */ |
127 | 150 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200); |
128 n = FONT_SLANT_NUMERIC (font_spec); | 151 if (n != -1 && n != STYLE_REF) |
129 if (n != -1) | 152 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0] |
130 traits |= (n > STYLE_REF) ? NSItalicFontMask | 153 forKey: NSFontWeightTrait]; |
131 : (n < STYLE_REF) ? NSUnitalicFontMask : 0; | 154 n = min (FONT_SLANT_NUMERIC (font_spec), 200); |
132 | 155 if (n != -1 && n != STYLE_REF) |
133 n = FONT_WIDTH_NUMERIC (font_spec); | 156 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0] |
134 if (n > -1) | 157 forKey: NSFontSlantTrait]; |
135 traits |= (n > STYLE_REF + 10) ? NSExpandedFontMask | 158 n = min (FONT_WIDTH_NUMERIC (font_spec), 200); |
136 : (n < STYLE_REF - 10) ? NSExpandedFontMask : 0; | 159 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10)) |
137 | 160 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0] |
138 /*fprintf (stderr, " returning traits = %u\n", traits); */ | 161 forKey: NSFontWidthTrait]; |
139 return traits; | 162 if ([tdict count] > 0) |
140 } | 163 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute]; |
141 | 164 |
142 | 165 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]; |
143 /* Converts NSArray of PS name, non-family part, weight, and traits to a | 166 if (family != nil) |
144 font backend font-entity. */ | 167 fdesc = [fdesc fontDescriptorWithFamily: family]; |
168 return fdesc; | |
169 } | |
170 | |
171 | |
172 /* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */ | |
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); |
175 | 203 /* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, |
176 if (NSFONT_TRACE) | 204 make_number (100 + 100 |
177 { | 205 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/ |
178 fprintf (stderr, "created font_entity:\n "); | 206 |
179 debug_print (font_entity); | 207 ASET (font_entity, FONT_SIZE_INDEX, make_number (0)); |
180 } | 208 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0)); |
181 | 209 ASET (font_entity, FONT_SPACING_INDEX, |
182 [suffix release]; | 210 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait |
183 free (escapedFamily); | 211 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL)); |
184 return font_entity; | 212 |
185 } | 213 ASET (font_entity, FONT_EXTRA_INDEX, extra); |
186 | 214 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil); |
187 | 215 |
188 /* Computes Hamming distance btwn two "vectors" of 0's and 1's. */ | 216 if (NSFONT_TRACE) |
189 static int | 217 { |
190 nsfont_trait_distance (unsigned int traits1, unsigned int traits2) | 218 fprintf (stderr, "created font_entity:\n "); |
191 { | 219 debug_print (font_entity); |
192 int i, d = 0; | 220 } |
193 for (i = 0; i < sizeof (unsigned int) * 8; i++) | 221 |
194 { | 222 free (escapedFamily); |
195 d += (traits1 & 0x1) ^ (traits2 & 0x1); | 223 return font_entity; |
196 traits1 >>= 1; | 224 } |
197 traits2 >>= 1; | 225 |
198 } | 226 |
199 return d; | 227 /* Default font entity. */ |
200 } | |
201 | |
202 | |
203 /* Default font entity based on Monaco. */ | |
204 static Lisp_Object | 228 static Lisp_Object |
205 nsfont_fallback_entity () | 229 ns_fallback_entity () |
206 { | 230 { |
207 NSString *family = [[NSFont userFixedPitchFontOfSize: 0] familyName]; | 231 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0] |
208 NSArray *famMemberSpec = [NSArray arrayWithObjects: family, @"", | 232 fontDescriptor], Qnil, NULL); |
209 [NSNumber numberWithUnsignedInt: 5], | 233 } |
210 [NSNumber numberWithUnsignedInt: 0], nil]; | 234 |
211 return nsfont_fmember_to_entity (family, famMemberSpec); | 235 |
212 } | 236 /* Utility: get width of a char c in screen font sfont */ |
237 static float | |
238 ns_char_width (NSFont *sfont, int c) | |
239 { | |
240 float w; | |
241 NSString *cstr = [NSString stringWithFormat: @"%c", c]; | |
242 #ifdef NS_IMPL_COCOA | |
243 NSGlyph glyph = [sfont glyphWithName: cstr]; | |
244 if (glyph) | |
245 { | |
246 float w = [sfont advancementForGlyph: glyph].width; | |
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; | |
386 } | |
387 | |
388 | |
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. */ | |
455 static Lisp_Object | |
456 ns_findfonts (Lisp_Object font_spec, BOOL isMatch) | |
457 { | |
458 Lisp_Object tem, list = Qnil; | |
459 NSFontDescriptor *fdesc, *desc; | |
460 NSMutableSet *fkeys; | |
461 NSArray *matchingDescs; | |
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; | |
521 } | |
522 | |
213 | 523 |
214 | 524 |
215 /* ========================================================================== | 525 /* ========================================================================== |
216 | 526 |
217 Font driver implementation | 527 Font driver implementation |
218 | 528 |
219 ========================================================================== */ | 529 ========================================================================== */ |
530 | |
220 | 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); |
224 static Lisp_Object nsfont_list_family (Lisp_Object frame); | 535 static Lisp_Object nsfont_list_family (Lisp_Object frame); |
263 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame); | 574 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame); |
264 return (dpyinfo->name_list_element); | 575 return (dpyinfo->name_list_element); |
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 |
443 /* List available families. The value is a list of family names | 609 /* List available families. The value is a list of family names |
444 (symbols). */ | 610 (symbols). */ |
460 | 626 |
461 return list; | 627 return list; |
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; |
497 Lisp_Object tem; | 644 Lisp_Object tem; |
498 NSRect brect; | 645 NSRect brect; |
504 | 651 |
505 /* 2008/03/08: The same font may end up being requested for different | 652 /* 2008/03/08: The same font may end up being requested for different |
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 |
514 if (NSFONT_TRACE) | 660 if (NSFONT_TRACE) |
515 { | 661 { |
525 } | 671 } |
526 | 672 |
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); | 681 |
536 } | 682 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */ |
537 | |
538 /* 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 |
548 weight: fixLeopardBug size: pixel_size]; | 692 weight: fixLeopardBug size: pixel_size]; |
549 } | 693 } |
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) |
559 { | 701 { |
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) |
571 NSLog (@"%@\n", nsfont); | 708 NSLog (@"%@\n", nsfont); |
572 | 709 |
574 cached = [fontCache objectForKey: nsfont]; | 711 cached = [fontCache objectForKey: nsfont]; |
575 if (cached != nil && !synthItal) | 712 if (cached != nil && !synthItal) |
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 } |
583 else | 720 else |
584 { | 721 { |
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 |
599 font_info->glyphs = (unsigned short **) | 735 font_info->glyphs = (unsigned short **) |
600 xmalloc (0x100 * sizeof (unsigned short *)); | 736 xmalloc (0x100 * sizeof (unsigned short *)); |
623 font->vertical_centering = 0; | 759 font->vertical_centering = 0; |
624 font->baseline_offset = 0; | 760 font->baseline_offset = 0; |
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 |
632 { | 767 { |
633 double expand, hshrink; | 768 double expand, hshrink; |
641 font_info->nsfont = nsfont; | 776 font_info->nsfont = nsfont; |
642 #endif | 777 #endif |
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); |
651 | 786 |
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; |
659 min_height = [sfont ascender] - [sfont descender]; | 794 min_height = [sfont ascender] - [sfont descender]; |
660 hd = full_height - min_height; | 795 hd = full_height - min_height; |
708 | 843 |
709 /* set up metrics portion of font struct */ | 844 /* set up metrics portion of font struct */ |
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); |
717 font->underline_position = lrint (font_info->underpos); | 852 font->underline_position = lrint (font_info->underpos); |
718 font->underline_thickness = lrint (font_info->underwidth); | 853 font->underline_thickness = lrint (font_info->underwidth); |
733 { | 868 { |
734 struct nsfont_info *font_info = (struct nsfont_info *)font; | 869 struct nsfont_info *font_info = (struct nsfont_info *)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 |
743 for (i =0; i<0x100; i++) | 877 for (i =0; i<0x100; i++) |
744 { | 878 { |
747 if (font_info->metrics[i]) | 881 if (font_info->metrics[i]) |
748 xfree (font_info->metrics[i]); | 882 xfree (font_info->metrics[i]); |
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 |
759 /* If FONT_ENTITY has a glyph for character C (Unicode code point), | 893 /* If FONT_ENTITY has a glyph for character C (Unicode code point), |
760 return 1. If not, return 0. If a font must be opened to check | 894 return 1. If not, return 0. If a font must be opened to check |
781 /* did we already cache this block? */ | 915 /* did we already cache this block? */ |
782 if (!font_info->glyphs[high]) | 916 if (!font_info->glyphs[high]) |
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 |
790 | 923 |
791 /* Perform the size computation of glyphs of FONT and fill in members | 924 /* Perform the size computation of glyphs of FONT and fill in members |
855 NSRect r; | 988 NSRect r; |
856 struct nsfont_info *font = ns_tmp_font; | 989 struct nsfont_info *font = ns_tmp_font; |
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) |
863 { | 998 { |
864 case NS_DUMPGLYPH_CURSOR: | 999 case NS_DUMPGLYPH_CURSOR: |
886 character widths added up because of layout processing. */ | 1021 character widths added up because of layout processing. */ |
887 { | 1022 { |
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 { |
904 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */ | 1055 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */ |
905 ns_glyph_metrics (font, hi); | 1056 ns_glyph_metrics (font, hi); |
917 r.size.width = twidth; | 1068 r.size.width = twidth; |
918 *c = 0; | 1069 *c = 0; |
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); |
926 int mbox_line_width = max (s->face->box_line_width, 0); | 1077 int mbox_line_width = max (s->face->box_line_width, 0); |
927 | 1078 |
1096 #endif /* NS_IMPL_COCOA */ | 1247 #endif /* NS_IMPL_COCOA */ |
1097 | 1248 |
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 |
1249 Font glyph and metrics caching functions | 1255 Font glyph and metrics caching functions |
1250 | 1256 |
1460 #endif /* NS_IMPL_COCOA */ | 1466 #endif /* NS_IMPL_COCOA */ |
1461 | 1467 |
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++) |
1473 fprintf (stderr, "%c", s->first_glyph[i].u.ch); | 1480 fprintf (stderr, "%c", s->first_glyph[i].u.ch); |
1474 fprintf (stderr, "\n"); | 1481 fprintf (stderr, "\n"); |
1475 } | 1482 } |
1476 | 1483 |
1477 | 1484 |
1478 | |
1479 void | 1485 void |
1480 syms_of_nsfont () | 1486 syms_of_nsfont () |
1481 { | 1487 { |
1482 nsfont_driver.type = Qns; | 1488 nsfont_driver.type = Qns; |
1483 register_font_driver (&nsfont_driver, NULL); | 1489 register_font_driver (&nsfont_driver, NULL); |