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);