* emacs-lisp-intro.texi (edebug): Fix typo.
[bpt/emacs.git] / src / nsfont.m
CommitLineData
a68fda4a
AR
1/* Font back-end driver for the NeXT/Open/GNUstep and MacOSX window system.
2 See font.h
76b6f707 3 Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
a68fda4a
AR
4
5This file is part of GNU Emacs.
6
32d235f8 7GNU Emacs is free software: you can redistribute it and/or modify
a68fda4a 8it under the terms of the GNU General Public License as published by
32d235f8
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
a68fda4a
AR
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
32d235f8 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
a68fda4a
AR
19
20Author: Adrian Robert (arobert@cogsci.ucsd.edu)
21*/
22
5a06864f
AR
23/* This should be the first include, as it may set up #defines affecting
24 interpretation of even the system includes. */
a68fda4a
AR
25#include "config.h"
26
27#include "lisp.h"
28#include "dispextern.h"
29#include "composite.h"
30#include "blockinput.h"
31#include "charset.h"
32#include "frame.h"
33#include "window.h"
34#include "fontset.h"
35#include "nsterm.h"
36#include "frame.h"
37#include "character.h"
38#include "font.h"
39
40#define NSFONT_TRACE 0
41
42extern Lisp_Object Qns;
43extern Lisp_Object Qnormal, Qbold, Qitalic, Qcondensed, Qexpanded;
44static Lisp_Object Qapple, Qroman, Qmedium;
a68fda4a
AR
45extern Lisp_Object Qappend;
46extern int ns_antialias_text, ns_use_qd_smoothing;
47extern float ns_antialias_threshold;
48extern int ns_tmp_flags;
49extern struct nsfont_info *ns_tmp_font;
50
51/* font glyph and metrics caching functions, implemented at end */
52static void ns_uni_to_glyphs (struct nsfont_info *font_info,
53 unsigned char block);
54static void ns_glyph_metrics (struct nsfont_info *font_info,
55 unsigned char block);
56
57
58/* ==========================================================================
59
60 Utilities
61
62 ========================================================================== */
63
64
65/* Replace spaces w/another character so emacs core font parsing routines
66 aren't thrown off. */
67static void
8840261a 68ns_escape_name (char *name)
a68fda4a
AR
69{
70 int i =0, len =strlen (name);
71 for ( ; i<len; i++)
72 if (name[i] == ' ')
73 name[i] = '_';
74}
75
76
77/* Reconstruct spaces in a font family name passed through emacs. */
78static void
8840261a 79ns_unescape_name (char *name)
a68fda4a
AR
80{
81 int i =0, len =strlen (name);
82 for ( ; i<len; i++)
83 if (name[i] == '_')
84 name[i] = ' ';
85}
86
87
88/* Extract family name from a font spec. */
89static NSString *
8840261a 90ns_get_family (Lisp_Object font_spec)
a68fda4a
AR
91{
92 Lisp_Object tem = AREF (font_spec, FONT_FAMILY_INDEX);
93 if (NILP (tem))
94 return nil;
95 else
96 {
97 char *tmp = strdup (SDATA (SYMBOL_NAME (tem)));
98 NSString *family;
8840261a
AR
99 ns_unescape_name (tmp);
100 /* For names hard-coded into emacs, like 'helvetica' for splash. */
101 tmp[0] = toupper (tmp[0]);
a68fda4a
AR
102 family = [NSString stringWithUTF8String: tmp];
103 free (tmp);
104 return family;
105 }
106}
107
108
8840261a
AR
109/* Return NSNumber or nil if attr is not set. */
110static NSNumber
111*ns_attribute_value (NSFontDescriptor *fdesc, NSString *trait)
a68fda4a 112{
8840261a
AR
113 NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
114 NSNumber *val = [tdict objectForKey: trait];
115 return val;
116}
a68fda4a 117
a68fda4a 118
8840261a
AR
119/* Return 0 if attr not set, else value (which might also be 0). */
120static float
121ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
122{
123 NSNumber *val = ns_attribute_value (fdesc, trait);
124 return val == nil ? 0.0 : [val floatValue];
125}
a68fda4a 126
a68fda4a 127
8840261a
AR
128/* Return whether font has attribute set to non-standard value. */
129static BOOL
130ns_has_attribute (NSFontDescriptor *fdesc, NSString *trait)
131{
132 float v = ns_attribute_fvalue (fdesc, trait);
133 return v < -0.25 || v > 0.25;
134}
135
136
137/* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
138 to NSFont descriptor. Information under extra only needed for matching. */
139#define STYLE_REF 100
140static NSFontDescriptor
141*ns_spec_to_descriptor(Lisp_Object font_spec)
142{
143 NSFontDescriptor *fdesc;
144 NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
145 NSMutableDictionary *tdict = [NSMutableDictionary new];
146 NSString *family = ns_get_family (font_spec);
147 float n;
148
149 /* add each attr in font_spec to fdAttrs.. */
150 n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
151 if (n != -1 && n != STYLE_REF)
152 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
153 forKey: NSFontWeightTrait];
154 n = min (FONT_SLANT_NUMERIC (font_spec), 200);
155 if (n != -1 && n != STYLE_REF)
156 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
157 forKey: NSFontSlantTrait];
158 n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
159 if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
160 [tdict setObject: [NSNumber numberWithFloat: (n - 100.0) / 100.0]
161 forKey: NSFontWidthTrait];
162 if ([tdict count] > 0)
163 [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
164
165 fdesc = [NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs];
166 if (family != nil)
167 fdesc = [fdesc fontDescriptorWithFamily: family];
168 return fdesc;
a68fda4a
AR
169}
170
171
8840261a 172/* Converts NSFont descriptor to FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, etc.. */
a68fda4a 173static Lisp_Object
8840261a 174ns_descriptor_to_entity (NSFontDescriptor *desc, Lisp_Object extra, char *style)
a68fda4a 175{
8840261a
AR
176 Lisp_Object font_entity = font_make_entity ();
177 /* NSString *psName = [desc postscriptName]; */
178 NSString *family = [desc objectForKey: NSFontFamilyAttribute];
179 char *escapedFamily = strdup ([family UTF8String]);
180 unsigned int traits = [desc symbolicTraits];
181
182 ns_escape_name (escapedFamily);
183
184 ASET (font_entity, FONT_TYPE_INDEX, Qns);
185 ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
186 ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
187 ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
188 ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
189
190 FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
191 traits & NSFontBoldTrait ? Qbold : Qmedium);
192/* FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
193 make_number (100 + 100
194 * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
195 FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
196 traits & NSFontItalicTrait ? Qitalic : Qnormal);
197/* FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
198 make_number (100 + 100
199 * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
200 FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
201 traits & NSFontCondensedTrait ? Qcondensed :
202 traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
203/* FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
204 make_number (100 + 100
205 * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
206
207 ASET (font_entity, FONT_SIZE_INDEX, make_number (0));
208 ASET (font_entity, FONT_AVGWIDTH_INDEX, make_number (0));
209 ASET (font_entity, FONT_SPACING_INDEX,
210 make_number([desc symbolicTraits] & NSFontMonoSpaceTrait
211 ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
212
213 ASET (font_entity, FONT_EXTRA_INDEX, extra);
214 ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
215
216 if (NSFONT_TRACE)
217 {
218 fprintf (stderr, "created font_entity:\n ");
219 debug_print (font_entity);
220 }
a68fda4a 221
8840261a
AR
222 free (escapedFamily);
223 return font_entity;
224}
a68fda4a 225
8840261a
AR
226
227/* Default font entity. */
228static Lisp_Object
229ns_fallback_entity ()
230{
231 return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
232 fontDescriptor], Qnil, NULL);
a68fda4a
AR
233}
234
235
8840261a
AR
236/* Utility: get width of a char c in screen font sfont */
237static float
238ns_char_width (NSFont *sfont, int c)
a68fda4a 239{
8840261a
AR
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. */
260static BOOL
261ns_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. */
281static 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?) */
299static 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. */
315static 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. */
341static void
342accumulate_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. */
356static 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;
a68fda4a
AR
386}
387
388
8840261a
AR
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. */
396static 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()
453must return something. Strategy is to drop family name from attribute
454matching set for match. */
a68fda4a 455static Lisp_Object
8840261a 456ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
a68fda4a 457{
8840261a
AR
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;
a68fda4a
AR
521}
522
523
8840261a 524
a68fda4a
AR
525/* ==========================================================================
526
527 Font driver implementation
528
529 ========================================================================== */
530
8840261a 531
a68fda4a
AR
532static Lisp_Object nsfont_get_cache (FRAME_PTR frame);
533static Lisp_Object nsfont_list (Lisp_Object frame, Lisp_Object font_spec);
534static Lisp_Object nsfont_match (Lisp_Object frame, Lisp_Object font_spec);
535static Lisp_Object nsfont_list_family (Lisp_Object frame);
536static Lisp_Object nsfont_open (FRAME_PTR f, Lisp_Object font_entity,
537 int pixel_size);
538static void nsfont_close (FRAME_PTR f, struct font *font);
539static int nsfont_has_char (Lisp_Object entity, int c);
540static unsigned int nsfont_encode_char (struct font *font, int c);
541static int nsfont_text_extents (struct font *font, unsigned int *code,
542 int nglyphs, struct font_metrics *metrics);
543static int nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
544 int with_background);
545
546struct font_driver nsfont_driver =
547 {
facfbbbd 548 0, /* Qns */
a68fda4a
AR
549 1, /* case sensitive */
550 nsfont_get_cache,
551 nsfont_list,
552 nsfont_match,
553 nsfont_list_family,
554 NULL, /*free_entity */
555 nsfont_open,
556 nsfont_close,
557 NULL, /* prepare_face */
558 NULL, /* done_face */
559 nsfont_has_char,
560 nsfont_encode_char,
561 nsfont_text_extents,
562 nsfont_draw,
563 /* excluded: get_bitmap, free_bitmap, get_outline, free_outline,
564 anchor_point, otf_capability, otf_driver,
565 start_for_frame, end_for_frame, shape */
566 };
567
568
569/* Return a cache of font-entities on FRAME. The cache must be a
570 cons whose cdr part is the actual cache area. */
571static Lisp_Object
572nsfont_get_cache (FRAME_PTR frame)
573{
574 Display_Info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
575 return (dpyinfo->name_list_element);
576}
577
578
8840261a
AR
579/* List fonts exactly matching with FONT_SPEC on FRAME. The value is a
580 **list** of font-entities. This and match () are sole APIs that allocate
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) */
a68fda4a
AR
591static Lisp_Object
592nsfont_list (Lisp_Object frame, Lisp_Object font_spec)
593{
8840261a 594 return ns_findfonts (font_spec, NO);
a68fda4a
AR
595}
596
597
598/* Return a font entity most closely maching with FONT_SPEC on
599 FRAME. The closeness is determined by the font backend, thus
8840261a
AR
600 `face-font-selection-order' is ignored here.
601 Properties to be considered are same as for list(). */
a68fda4a
AR
602static Lisp_Object
603nsfont_match (Lisp_Object frame, Lisp_Object font_spec)
604{
8840261a 605 return ns_findfonts(font_spec, YES);
a68fda4a
AR
606}
607
608
609/* List available families. The value is a list of family names
610 (symbols). */
611static Lisp_Object
612nsfont_list_family (Lisp_Object frame)
613{
614 Lisp_Object list = Qnil;
615 NSEnumerator *families =
616 [[[NSFontManager sharedFontManager] availableFontFamilies]
617 objectEnumerator];
618 NSString *family;
619 while (family = [families nextObject])
620 list = Fcons (intern ([family UTF8String]), list);
df2142db 621 /* FIXME: escape the name? */
a68fda4a
AR
622
623 if (NSFONT_TRACE)
624 fprintf (stderr, "nsfont: list families returning %d entries\n",
625 XINT (Flength (list)));
626
627 return list;
628}
629
630
a68fda4a
AR
631/* Open a font specified by FONT_ENTITY on frame F. If the font is
632 scalable, open it with PIXEL_SIZE. */
633static Lisp_Object
634nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
635{
636 BOOL synthItal;
8840261a 637 unsigned int traits = 0;
a68fda4a
AR
638 struct nsfont_info *font_info;
639 struct font *font;
8840261a 640 NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
a68fda4a
AR
641 NSFontManager *fontMgr = [NSFontManager sharedFontManager];
642 NSString *family;
643 NSFont *nsfont, *sfont;
644 Lisp_Object tem;
645 NSRect brect;
646 Lisp_Object font_object;
647 int i;
648 int fixLeopardBug;
a68fda4a 649 static NSMutableDictionary *fontCache = nil;
8d0e382e 650 NSNumber *cached;
a68fda4a
AR
651
652 /* 2008/03/08: The same font may end up being requested for different
653 entities, due to small differences in numeric values or other issues,
654 or for different copies of the same entity. Therefore we cache to
655 avoid creating multiple struct font objects (with metrics cache, etc.)
8840261a 656 for the same NSFont object. */
a68fda4a
AR
657 if (fontCache == nil)
658 fontCache = [[NSMutableDictionary alloc] init];
a68fda4a
AR
659
660 if (NSFONT_TRACE)
661 {
662 fprintf (stderr, "nsfont: open size %d of fontentity:\n ", pixel_size);
663 debug_print (font_entity);
664 }
665
666 if (pixel_size <= 0)
667 {
668 /* try to get it out of frame params */
669 Lisp_Object tem = get_frame_param (f, Qfontsize);
670 pixel_size = NILP (tem) ? 0 : XFASTINT (tem);
671 }
672
673 tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
674 synthItal = !NILP (tem) && !strncmp ("synthItal", SDATA (SYMBOL_NAME (tem)),
675 9);
8840261a
AR
676 family = ns_get_family (font_entity);
677 if (ns_has_attribute (fontDesc, NSFontWeightTrait))
678 traits |= NSBoldFontMask;
679 if (ns_has_attribute (fontDesc, NSFontSlantTrait))
680 traits |= NSItalicFontMask;
a68fda4a 681
8840261a 682 /* see http://cocoadev.com/forums/comments.php?DiscussionID=74 */
a68fda4a
AR
683 fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
684 nsfont = [fontMgr fontWithFamily: family
685 traits: traits weight: fixLeopardBug
686 size: pixel_size];
687 /* if didn't find, try synthetic italic */
8840261a 688 if (nsfont == nil && synthItal)
a68fda4a
AR
689 {
690 nsfont = [fontMgr fontWithFamily: family
691 traits: traits & ~NSItalicFontMask
692 weight: fixLeopardBug size: pixel_size];
693 }
694#ifdef NS_IMPL_COCOA
695 /* LastResort not really a family */
696 if (nsfont == nil && [@"LastResort" isEqualToString: family])
a68fda4a 697 nsfont = [NSFont fontWithName: @"LastResort" size: pixel_size];
a68fda4a
AR
698#endif
699
700 if (nsfont == nil)
701 {
702 message_with_string ("*** Warning: font in family '%s' not found",
703 build_string ([family UTF8String]), 1);
704 nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
a68fda4a
AR
705 }
706
8d0e382e
AR
707 if (NSFONT_TRACE)
708 NSLog (@"%@\n", nsfont);
1bc98b35 709
8d0e382e
AR
710 /* Check the cache */
711 cached = [fontCache objectForKey: nsfont];
712 if (cached != nil && !synthItal)
713 {
714 if (NSFONT_TRACE)
715 fprintf(stderr, "*** nsfont_open CACHE HIT!\n");
8840261a 716 /* FIXME: Cast from (unsigned long) to Lisp_Object. */
86fa089e
SM
717 XHASH (font_object) = [cached unsignedLongValue];
718 return font_object;
8d0e382e
AR
719 }
720 else
721 {
722 font_object = font_make_object (VECSIZE (struct nsfont_info),
723 font_entity, pixel_size);
724 if (!synthItal)
8840261a
AR
725 [fontCache setObject: [NSNumber numberWithUnsignedLong:
726 (unsigned long) XHASH (font_object)]
727 forKey: nsfont];
8d0e382e
AR
728 }
729
730 font_info = (struct nsfont_info *) XFONT_OBJECT (font_object);
8840261a 731 font = (struct font *) font_info;
8d0e382e
AR
732 if (!font)
733 return Qnil; /* FIXME: other terms do, but return Qnil causes segfault */
a68fda4a 734
15034960 735 font_info->glyphs = (unsigned short **)
a68fda4a 736 xmalloc (0x100 * sizeof (unsigned short *));
15034960 737 font_info->metrics = (struct font_metrics **)
a68fda4a
AR
738 xmalloc (0x100 * sizeof (struct font_metrics *));
739 if (!font_info->glyphs || !font_info->metrics)
facfbbbd 740 return Qnil;
a68fda4a
AR
741 bzero (font_info->glyphs, 0x100 * sizeof (unsigned short *));
742 bzero (font_info->metrics, 0x100 * sizeof (struct font_metrics *));
743
8d0e382e 744 BLOCK_INPUT;
a68fda4a
AR
745
746 /* for metrics */
747 sfont = [nsfont screenFont];
748 if (sfont == nil)
749 sfont = nsfont;
750
751 /* non-metric backend font struct fields */
752 font = (struct font *) font_info;
753 font->pixel_size = [sfont pointSize];
754 font->driver = &nsfont_driver;
755 font->encoding_type = FONT_ENCODING_NOT_DECIDED;
756 font->encoding_charset = -1;
757 font->repertory_charset = -1;
758 font->default_ascent = 0;
759 font->vertical_centering = 0;
760 font->baseline_offset = 0;
761 font->relative_compose = 0;
762 font->font_encoder = NULL;
763
a68fda4a
AR
764 font->props[FONT_FORMAT_INDEX] = Qns;
765 font->props[FONT_FILE_INDEX] = Qnil;
766
767 {
7fa87f63 768 double expand, hshrink;
a68fda4a
AR
769 float full_height, min_height, hd;
770 const char *fontName = [[nsfont fontName] UTF8String];
771 int len = strlen (fontName);
772
773#ifdef NS_IMPL_GNUSTEP
774 font_info->nsfont = sfont;
775#else
776 font_info->nsfont = nsfont;
777#endif
778 [font_info->nsfont retain];
779
780 /* set up ns_font (defined in nsgui.h) */
8840261a
AR
781 font_info->name = (char *)xmalloc (strlen (fontName) + 1);
782 bcopy (fontName, font_info->name, strlen (fontName) + 1);
a68fda4a
AR
783 font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
784 font_info->ital =
785 synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
786
787 /* Metrics etc.; some fonts return an unusually large max advance, so we
788 only use it for fonts that have wide characters. */
789 font_info->width = ([sfont numberOfGlyphs] > 2000) ?
8840261a 790 [sfont maximumAdvancement].width : ns_char_width (sfont, '0');
a68fda4a
AR
791
792 brect = [sfont boundingRectForFont];
793 full_height = brect.size.height;
794 min_height = [sfont ascender] - [sfont descender];
795 hd = full_height - min_height;
796
c6c62e78 797 /* standard height, similar to Carbon. Emacs.app: was 0.5 by default. */
7fa87f63 798 expand = 0.0;
c6c62e78 799 hshrink = 1.0;
a68fda4a 800
a68fda4a
AR
801 font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */
802 font_info->underwidth = [sfont underlineThickness];
803 font_info->size = font->pixel_size;
804 font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2);
805
806 /* max bounds */
807 font_info->max_bounds.ascent =
808 lrint (hshrink * [sfont ascender] + expand * hd/2);
809 font_info->max_bounds.descent =
810 -lrint (hshrink* [sfont descender] - expand*hd/2);
811 font_info->height =
812 font_info->max_bounds.ascent + font_info->max_bounds.descent;
813 font_info->max_bounds.width = lrint (font_info->width);
814 font_info->max_bounds.lbearing = lrint (brect.origin.x);
815 font_info->max_bounds.rbearing =
816 lrint (brect.size.width - font_info->width);
a68fda4a
AR
817
818#ifdef NS_IMPL_COCOA
819 /* set up synthItal and the CG font */
820 font_info->synthItal = synthItal;
821 {
822 ATSFontRef atsFont = ATSFontFindFromPostScriptName
823 ((CFStringRef)[nsfont fontName], kATSOptionFlagsDefault);
824
825 if (atsFont == kATSFontRefUnspecified)
826 {
827 /* see if we can get it by dropping italic (then synthesizing) */
828 atsFont = ATSFontFindFromPostScriptName ((CFStringRef)
829 [[fontMgr convertFont: nsfont toNotHaveTrait: NSItalicFontMask]
830 fontName], kATSOptionFlagsDefault);
831 if (atsFont != kATSFontRefUnspecified)
832 font_info->synthItal = YES;
833 else
834 {
835 /* last resort fallback */
836 atsFont = ATSFontFindFromPostScriptName
837 ((CFStringRef)@"Monaco", kATSOptionFlagsDefault);
838 }
839 }
840 font_info->cgfont = CGFontCreateWithPlatformFont ((void*)&atsFont);
841 }
842#endif
843
844 /* set up metrics portion of font struct */
845 font->ascent = [sfont ascender];
846 font->descent = -[sfont descender];
df2142db 847 font->min_width = [sfont widthOfString: @"|"]; /* FIXME */
8840261a 848 font->space_width = lrint (ns_char_width (sfont, ' '));
a68fda4a
AR
849 font->average_width = lrint (font_info->width);
850 font->max_width = lrint (font_info->max_bounds.width);
851 font->height = lrint (font_info->height);
852 font->underline_position = lrint (font_info->underpos);
853 font->underline_thickness = lrint (font_info->underwidth);
854
855 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
856 font->props[FONT_FULLNAME_INDEX] =
857 make_unibyte_string (font_info->name, strlen (font_info->name));
858 }
859 UNBLOCK_INPUT;
860
861 return font_object;
862}
863
864
865/* Close FONT on frame F. */
866static void
867nsfont_close (FRAME_PTR f, struct font *font)
868{
869 struct nsfont_info *font_info = (struct nsfont_info *)font;
870 int i;
871
df2142db 872 /* FIXME: this occurs apparently due to same failure to detect same font
8840261a 873 that causes need for cache in nsfont_open () */
a68fda4a
AR
874 if (!font_info)
875 return;
876
877 for (i =0; i<0x100; i++)
878 {
879 if (font_info->glyphs[i])
880 xfree (font_info->glyphs[i]);
881 if (font_info->metrics[i])
882 xfree (font_info->metrics[i]);
883 }
884 [font_info->nsfont release];
885#ifdef NS_IMPL_COCOA
8840261a 886 CGFontRelease (font_info->cgfont);
a68fda4a 887#endif
8840261a
AR
888 xfree (font_info->name);
889 xfree (font_info);
a68fda4a
AR
890}
891
892
893/* If FONT_ENTITY has a glyph for character C (Unicode code point),
894 return 1. If not, return 0. If a font must be opened to check
895 it, return -1. */
896static int
897nsfont_has_char (Lisp_Object entity, int c)
898{
899 return -1;
900}
901
902
903/* Return a glyph code of FONT for character C (Unicode code point).
904 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
905static unsigned int
906nsfont_encode_char (struct font *font, int c)
907{
908 struct nsfont_info *font_info = (struct nsfont_info *)font;
909 unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
910 unsigned short g;
911
912 if (c > 0xFFFF)
913 return FONT_INVALID_CODE;
914
915 /* did we already cache this block? */
916 if (!font_info->glyphs[high])
917 ns_uni_to_glyphs (font_info, high);
918
919 g = font_info->glyphs[high][low];
a68fda4a
AR
920 return g == 0xFFFF ? FONT_INVALID_CODE : g;
921}
922
923
924/* Perform the size computation of glyphs of FONT and fill in members
925 of METRICS. The glyphs are specified by their glyph codes in
926 CODE (length NGLYPHS). */
927static int
928nsfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
929 struct font_metrics *metrics)
930{
931 struct nsfont_info *font_info = (struct nsfont_info *)font;
932 struct font_metrics *pcm;
933 unsigned char high, low;
934 int totalWidth = 0;
935 int i;
936
937 bzero (metrics, sizeof (struct font_metrics));
938
939 for (i =0; i<nglyphs; i++)
940 {
941 /* get metrics for this glyph, filling cache if need be */
df2142db
AR
942 /* TODO: get metrics for whole string from an NSLayoutManager
943 (if not too slow) */
a68fda4a
AR
944 high = (code[i] & 0xFF00) >> 8;
945 low = code[i] & 0x00FF;
946 if (!font_info->metrics[high])
947 ns_glyph_metrics (font_info, high);
948 pcm = &(font_info->metrics[high][low]);
949
950 if (metrics->lbearing > totalWidth + pcm->lbearing)
951 metrics->lbearing = totalWidth + pcm->lbearing;
952 if (metrics->rbearing < totalWidth + pcm->rbearing)
953 metrics->rbearing = totalWidth + pcm->rbearing;
954 if (metrics->ascent < pcm->ascent)
955 metrics->ascent = pcm->ascent;
956 if (metrics->descent < pcm->descent)
957 metrics->descent = pcm->descent;
958
959 totalWidth += pcm->width;
960 }
961
962 metrics->width = totalWidth;
963
964 return totalWidth; /* not specified in doc, but xfont.c does it */
965}
966
967
968/* Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
969 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
970 is nonzero, fill the background in advance. It is assured that
971 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
972static int
973nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
974 int with_background)
975/* NOTE: focus and clip must be set
976 also, currently assumed (true in nsterm.m call) from ==0, to ==nchars */
977{
978 static char cbuf[1024];
979 char *c = cbuf;
980#ifdef NS_IMPL_GNUSTEP
981 static float advances[1024];
982 float *adv = advances;
983#else
984 static CGSize advances[1024];
985 CGSize *adv = advances;
986#endif
987 struct face *face;
988 NSRect r;
989 struct nsfont_info *font = ns_tmp_font;
990 NSColor *col, *bgCol;
991 unsigned short *t = s->char2b;
992 int i, len;
8840261a
AR
993 char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
994 int end = isComposite ? s->cmp_to : s->nchars;
a68fda4a
AR
995
996 /* Select face based on input flags */
997 switch (ns_tmp_flags)
998 {
999 case NS_DUMPGLYPH_CURSOR:
1000 face = s->face;
1001 break;
1002 case NS_DUMPGLYPH_MOUSEFACE:
1003 face = FACE_FROM_ID (s->f,
1004 FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
1005 if (!face)
1006 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
1007 break;
1008 default:
1009 face = s->face;
1010 }
1011
1012 r.origin.x = s->x;
1013 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1014 r.origin.x += abs (s->face->box_line_width);
1015
1016 r.origin.y = s->y;
1017 r.size.height = FONT_HEIGHT (font);
1018
1019 /* Convert UTF-16 (?) to UTF-8 and determine advances. Note if we just ask
1020 NS to render the string, it will come out differently from the individual
1021 character widths added up because of layout processing. */
1022 {
1023 XCharStruct *cs;
1024 int cwidth, twidth = 0;
1025 int hi, lo;
df2142db 1026 /* FIXME: composition: no vertical displacement is considered. */
81cfe31c 1027 t += s->cmp_from; /* advance into composition */
8840261a 1028 for (i = s->cmp_from; i < end; i++, t++)
a68fda4a
AR
1029 {
1030 hi = (*t & 0xFF00) >> 8;
1031 lo = *t & 0x00FF;
1032 if (isComposite)
1033 {
8840261a
AR
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 }
a68fda4a
AR
1052 }
1053 else
1054 {
df2142db 1055 if (!font->metrics[hi]) /* FIXME: why/how can we need this now? */
a68fda4a
AR
1056 ns_glyph_metrics (font, hi);
1057 cwidth = font->metrics[hi][lo].width;
1058 }
1059 twidth += cwidth;
1060#ifdef NS_IMPL_GNUSTEP
1061 *adv++ = cwidth;
1062 CHAR_STRING_ADVANCE (*t, c); /* this converts the char to UTF-8 */
1063#else
1064 (*adv++).width = cwidth;
1065#endif
1066 }
1067 len = adv - advances;
1068 r.size.width = twidth;
1069 *c = 0;
1070 }
1071
1072 /* fill background if requested */
8840261a 1073 if (with_background && !isComposite)
a68fda4a
AR
1074 {
1075 NSRect br = r;
1076 int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
1077 int mbox_line_width = max (s->face->box_line_width, 0);
1078
1079 if (s->row->full_width_p)
1080 {
1081 if (br.origin.x <= fibw + 1 + mbox_line_width)
1082 {
1083 br.size.width += br.origin.x - mbox_line_width;
1084 br.origin.x = mbox_line_width;
1085 }
1086 if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
1087 <= fibw+1)
1088 br.size.width += fibw;
1089 }
1090 if (s->face->box == FACE_NO_BOX)
1091 {
1092 /* expand unboxed top row over internal border */
1093 if (br.origin.y <= fibw + 1 + mbox_line_width)
1094 {
1095 br.size.height += br.origin.y;
1096 br.origin.y = 0;
1097 }
1098 }
1099 else
1100 {
1101 int correction = abs (s->face->box_line_width)+1;
1102 br.origin.y += correction;
1103 br.size.height -= 2*correction;
1104 br.origin.x += correction;
1105 br.size.width -= 2*correction;
1106 }
1107
1108 if (!s->face->stipple)
45d325c4 1109 [(NS_FACE_BACKGROUND (face) != 0
a68fda4a
AR
1110 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1111 : FRAME_BACKGROUND_COLOR (s->f)) set];
1112 else
1113 {
1114 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
1115 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
1116 }
1117 NSRectFill (br);
1118 }
1119
1120
1121 /* set up for character rendering */
1122 r.origin.y += font->voffset + (s->height - font->height)/2;
1123
15034960 1124 col = (NS_FACE_FOREGROUND (face) != 0
a68fda4a
AR
1125 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
1126 : FRAME_FOREGROUND_COLOR (s->f));
df2142db 1127 /* FIXME: find another way to pass this */
a68fda4a 1128 bgCol = (ns_tmp_flags != NS_DUMPGLYPH_FOREGROUND ? nil
45d325c4 1129 : (NS_FACE_BACKGROUND (face) != 0
a68fda4a
AR
1130 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
1131 : FRAME_BACKGROUND_COLOR (s->f)));
1132
1133 /* render under GNUstep using DPS */
1134#ifdef NS_IMPL_GNUSTEP
1135 {
1136 NSGraphicsContext *context = GSCurrentContext ();
1137
1138 DPSgsave (context);
1139 [font->nsfont set];
1140
1141 /* do erase if "foreground" mode */
1142 if (bgCol != nil)
1143 {
1144 [bgCol set];
1145 DPSmoveto (context, r.origin.x, r.origin.y);
1146/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
1147 DPSxshow (context, cbuf, advances, len);
1148 DPSstroke (context);
1149 [col set];
1150/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
1151 }
1152
1153 /* do underline */
1154 if (face->underline_p)
1155 {
f2f7f42c 1156 if (face->underline_color != 0)
a68fda4a
AR
1157 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1158 else
1159 [col set];
1160 DPSmoveto (context, r.origin.x, r.origin.y + font->underpos);
1161 DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos);
f2f7f42c 1162 if (face->underline_color != 0)
a68fda4a
AR
1163 [col set];
1164 }
1165 else
1166 [col set];
1167
1168 /* draw with DPSxshow () */
1169 DPSmoveto (context, r.origin.x, r.origin.y);
1170 DPSxshow (context, cbuf, advances, len);
1171 DPSstroke (context);
1172
1173 DPSgrestore (context);
1174 return to-from;
1175 }
1176
1177#else /* NS_IMPL_COCOA */
1178 {
1179 CGContextRef gcontext =
1180 [[NSGraphicsContext currentContext] graphicsPort];
1181 static CGAffineTransform fliptf;
1182 static BOOL firstTime = YES;
1183
1184 if (firstTime)
1185 {
1186 firstTime = NO;
1187 fliptf = CGAffineTransformMakeScale (1.0, -1.0);
1188 }
1189
1190 CGContextSaveGState (gcontext);
1191
1192 fliptf.c = font->synthItal ? Fix2X (kATSItalicQDSkew) : 0.0;
1193
1194 CGContextSetFont (gcontext, font->cgfont);
1195 CGContextSetFontSize (gcontext, font->size);
2f462d73 1196 if (ns_antialias_text == Qnil || font->size <= ns_antialias_threshold)
a68fda4a
AR
1197 CGContextSetShouldAntialias (gcontext, 0);
1198 else
1199 CGContextSetShouldAntialias (gcontext, 1);
5c976973 1200 if (EQ (ns_use_qd_smoothing, Qt))
a68fda4a
AR
1201 CGContextSetFontRenderingMode (gcontext, 2); /* 0 is Cocoa, 2 is QD */
1202
1203 CGContextSetTextMatrix (gcontext, fliptf);
1204
1205 if (bgCol != nil)
1206 {
1207 /* foreground drawing; erase first to avoid overstrike */
1208 [bgCol set];
1209 CGContextSetTextDrawingMode (gcontext, kCGTextFillStroke);
1210 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
1211 CGContextShowGlyphsWithAdvances (gcontext, s->char2b, advances, len);
1212 CGContextSetTextDrawingMode (gcontext, kCGTextFill);
1213 }
1214
1215 if (face->underline_p)
1216 {
15034960 1217 if (face->underline_color != 0)
a68fda4a
AR
1218 [ns_lookup_indexed_color (face->underline_color, s->f) set];
1219 else
1220 [col set];
1221 CGContextBeginPath (gcontext);
1222 CGContextMoveToPoint (gcontext,
1223 r.origin.x, r.origin.y + font->underpos);
1224 CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width,
1225 r.origin.y + font->underpos);
1226 CGContextStrokePath (gcontext);
15034960 1227 if (face->underline_color != 0)
a68fda4a
AR
1228 [col set];
1229 }
1230 else
1231 [col set];
1232
1233 CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y);
93c7fcf8 1234 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
a68fda4a
AR
1235 advances, len);
1236
1237 if (face->overstrike)
1238 {
1239 CGContextSetTextPosition (gcontext, r.origin.x+0.5, r.origin.y);
93c7fcf8 1240 CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from,
a68fda4a
AR
1241 advances, len);
1242 }
1243
1244 CGContextRestoreGState (gcontext);
1245 return;
1246 }
1247#endif /* NS_IMPL_COCOA */
1248
1249}
1250
1251
a68fda4a
AR
1252
1253/* ==========================================================================
1254
1255 Font glyph and metrics caching functions
1256
1257 ========================================================================== */
1258
1259/* Find and cache corresponding glyph codes for unicode values in given
1260 hi-byte block of 256. */
1261static void
1262ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned char block)
1263{
1264#ifdef NS_IMPL_COCOA
1265 static EmacsGlyphStorage *glyphStorage;
1266 static char firstTime = 1;
1267#endif
1268 unichar *unichars = xmalloc (0x101 * sizeof (unichar));
1269 unsigned int i, g, idx;
1270 unsigned short *glyphs;
1271
1272 if (NSFONT_TRACE)
1273 fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
1274 font_info, block);
1275
1276 BLOCK_INPUT;
1277
1278#ifdef NS_IMPL_COCOA
1279 if (firstTime)
1280 {
1281 firstTime = 0;
1282 glyphStorage = [[EmacsGlyphStorage alloc] initWithCapacity: 0x100];
1283 }
1284#endif
1285
1286 font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
1287 if (!unichars || !(font_info->glyphs[block]))
1288 abort ();
1289
1290 /* create a string containing all unicode characters in this block */
1291 for (idx = block<<8, i =0; i<0x100; idx++, i++)
1292 if (idx < 0xD800 || idx > 0xDFFF)
1293 unichars[i] = idx;
1294 else
1295 unichars[i] = 0xFEFF;
1296 unichars[0x100] = 0;
1297
1298 {
1299#ifdef NS_IMPL_COCOA
1300 NSString *allChars = [[NSString alloc]
1301 initWithCharactersNoCopy: unichars
1302 length: 0x100
1303 freeWhenDone: NO];
1304 NSGlyphGenerator *glyphGenerator = [NSGlyphGenerator sharedGlyphGenerator];
1305 /*NSCharacterSet *coveredChars = [nsfont coveredCharacterSet]; */
1306 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1307 unsigned int gInd =0, cInd =0;
1308
1309 [glyphStorage setString: allChars font: font_info->nsfont];
1310 [glyphGenerator generateGlyphsForGlyphStorage: glyphStorage
1311 desiredNumberOfCharacters: glyphStorage->maxChar
1312 glyphIndex: &gInd characterIndex: &cInd];
1313#endif
1314 glyphs = font_info->glyphs[block];
1315 for (i =0; i<0x100; i++, glyphs++)
1316 {
1317#ifdef NS_IMPL_GNUSTEP
1318 g = unichars[i];
1319#else
1320 g = glyphStorage->cglyphs[i];
df2142db 1321 /* TODO: is this a good check? maybe need to use coveredChars.. */
a68fda4a
AR
1322 if (g > numGlyphs)
1323 g = 0xFFFF; /* hopefully unused... */
1324#endif
1325 *glyphs = g;
1326 }
1327
1328#ifdef NS_IMPL_COCOA
1329 [allChars release];
1330#endif
1331 }
1332
1333 UNBLOCK_INPUT;
1334 xfree (unichars);
1335}
1336
1337
1338/* Determine and cache metrics for corresponding glyph codes in given
1339 hi-byte block of 256. */
1340static void
1341ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
1342{
1343 unsigned int i, g;
1344 unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
1345 NSFont *sfont;
1346 struct font_metrics *metrics;
1347
1348 if (NSFONT_TRACE)
1349 fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
1350 font_info, block);
1351
1352#ifdef NS_IMPL_GNUSTEP
1353 /* not implemented yet (as of startup 0.18), so punt */
1354 if (numGlyphs == 0)
1355 numGlyphs = 0x10000;
1356#endif
1357
1358 BLOCK_INPUT;
1359 sfont = [font_info->nsfont screenFont];
1360
1361 font_info->metrics[block] = xmalloc (0x100 * sizeof (struct font_metrics));
1362 bzero (font_info->metrics[block], 0x100 * sizeof (struct font_metrics));
1363 if (!(font_info->metrics[block]))
1364 abort ();
1365
1366 metrics = font_info->metrics[block];
1367 for (g = block<<8, i =0; i<0x100 && g < numGlyphs; g++, i++, metrics++)
1368 {
1369 float w, lb, rb;
1370 NSRect r = [sfont boundingRectForGlyph: g];
1371
1372#ifdef NS_IMPL_GNUSTEP
1373 {
1374 /* lord help us */
1375 NSString *s = [NSString stringWithFormat: @"%c", g];
1376 w = [sfont widthOfString: s];
1377 }
1378#else
1379 w = [sfont advancementForGlyph: g].width;
1380#endif
1381 w = max (w, 2.0);
1382 metrics->width = lrint (w);
1383
1384 lb = r.origin.x;
1385 rb = r.size.width - w;
1386 if (lb < 0)
1387 metrics->lbearing = round (lb);
1388 if (font_info->ital)
1389 rb += 0.22 * font_info->height;
1390 metrics->rbearing = lrint (w + rb);
1391
1392 metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
1393 /*lrint (hshrink * [sfont ascender] + expand * hd/2); */
1394 metrics->ascent = r.size.height - metrics->descent;
1395/*-lrint (hshrink* [sfont descender] - expand * hd/2); */
1396 }
1397 UNBLOCK_INPUT;
1398}
1399
1400
1401#ifdef NS_IMPL_COCOA
1402/* helper for font glyph setup */
1403@implementation EmacsGlyphStorage
1404
1405- init
1406{
1407 return [self initWithCapacity: 1024];
1408}
1409
1410- initWithCapacity: (unsigned long) c
1411{
1412 self = [super init];
1413 maxChar = 0;
1414 maxGlyph = 0;
1415 dict = [NSMutableDictionary new];
1416 cglyphs = (CGGlyph *)xmalloc (c * sizeof (CGGlyph));
1417 return self;
1418}
1419
1420- (void) dealloc
1421{
1422 if (attrStr != nil)
1423 [attrStr release];
1424 [dict release];
1425 xfree (cglyphs);
1426 [super dealloc];
1427}
1428
1429- (void) setString: (NSString *)str font: (NSFont *)font
1430{
1431 [dict setObject: font forKey: NSFontAttributeName];
1432 attrStr = [[NSAttributedString alloc] initWithString: str attributes: dict];
1433 maxChar = [str length];
1434 maxGlyph = 0;
1435}
1436
1437/* NSGlyphStorage protocol */
1438- (unsigned int)layoutOptions
1439{
1440 return 0;
1441}
1442
1443- (NSAttributedString *)attributedString
1444{
1445 return attrStr;
1446}
1447
1448- (void)insertGlyphs: (const NSGlyph *)glyphs length: (unsigned int)length
1449 forStartingGlyphAtIndex: (unsigned int)glyphIndex
1450 characterIndex: (unsigned int)charIndex
1451{
1452 len = glyphIndex+length;
1453 for (i =glyphIndex; i<len; i++)
1454 cglyphs[i] = glyphs[i-glyphIndex];
1455 if (len > maxGlyph)
1456 maxGlyph = len;
1457}
1458
1459- (void)setIntAttribute: (int)attributeTag value: (int)val
1460 forGlyphAtIndex: (unsigned)glyphIndex
1461{
1462 return;
1463}
1464
1465@end
1466#endif /* NS_IMPL_COCOA */
1467
1468
1469/* Debugging */
1470void
8840261a 1471ns_dump_glyphstring (struct glyph_string *s)
a68fda4a
AR
1472{
1473 int i;
1474
8840261a
AR
1475 fprintf (stderr, "Glyph string len = %d at (%d, %d) overhang (%d, %d),"
1476"overlap = %d, bg_filled = %d:",
a68fda4a
AR
1477 s->nchars, s->x, s->y, s->left_overhang, s->right_overhang,
1478 s->row->overlapping_p, s->background_filled_p);
1479 for (i =0; i<s->nchars; i++)
1480 fprintf (stderr, "%c", s->first_glyph[i].u.ch);
1481 fprintf (stderr, "\n");
1482}
1483
1484
a68fda4a
AR
1485void
1486syms_of_nsfont ()
1487{
1488 nsfont_driver.type = Qns;
1489 register_font_driver (&nsfont_driver, NULL);
1490 DEFSYM (Qapple, "apple");
1491 DEFSYM (Qroman, "roman");
1492 DEFSYM (Qmedium, "medium");
1493}
0ae1e5e5 1494
2f8e74bb 1495// arch-tag: d6c3c6f0-62de-4978-8b1e-b7966fe02cae