/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkfont.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkfont.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkfont.c revision 69 by dashley, Sat Nov 5 10:54:17 2016 UTC projs/dtats/trunk/shared_source/c_tk_base_7_5_w_mods/tkfont.c revision 98 by dashley, Sun Dec 18 00:57:31 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2    
3  /*  /*
4   * tkFont.c --   * tkFont.c --
5   *   *
6   *      This file maintains a database of fonts for the Tk toolkit.   *      This file maintains a database of fonts for the Tk toolkit.
7   *      It also provides several utility procedures for measuring and   *      It also provides several utility procedures for measuring and
8   *      displaying text.   *      displaying text.
9   *   *
10   * Copyright (c) 1990-1994 The Regents of the University of California.   * Copyright (c) 1990-1994 The Regents of the University of California.
11   * Copyright (c) 1994-1998 Sun Microsystems, Inc.   * Copyright (c) 1994-1998 Sun Microsystems, Inc.
12   *   *
13   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
14   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15   *   *
16   * RCS: @(#) $Id: tkfont.c,v 1.1.1.1 2001/06/13 05:00:58 dtashley Exp $   * RCS: @(#) $Id: tkfont.c,v 1.1.1.1 2001/06/13 05:00:58 dtashley Exp $
17   */   */
18    
19  #include "tkPort.h"  #include "tkPort.h"
20  #include "tkInt.h"  #include "tkInt.h"
21  #include "tkFont.h"  #include "tkFont.h"
22    
23  /*  /*
24   * The following structure is used to keep track of all the fonts that   * The following structure is used to keep track of all the fonts that
25   * exist in the current application.  It must be stored in the   * exist in the current application.  It must be stored in the
26   * TkMainInfo for the application.   * TkMainInfo for the application.
27   */   */
28    
29  typedef struct TkFontInfo {  typedef struct TkFontInfo {
30      Tcl_HashTable fontCache;    /* Map a string to an existing Tk_Font.      Tcl_HashTable fontCache;    /* Map a string to an existing Tk_Font.
31                                   * Keys are string font names, values are                                   * Keys are string font names, values are
32                                   * TkFont pointers. */                                   * TkFont pointers. */
33      Tcl_HashTable namedTable;   /* Map a name to a set of attributes for a      Tcl_HashTable namedTable;   /* Map a name to a set of attributes for a
34                                   * font, used when constructing a Tk_Font from                                   * font, used when constructing a Tk_Font from
35                                   * a named font description.  Keys are                                   * a named font description.  Keys are
36                                   * strings, values are NamedFont pointers. */                                   * strings, values are NamedFont pointers. */
37      TkMainInfo *mainPtr;        /* Application that owns this structure. */      TkMainInfo *mainPtr;        /* Application that owns this structure. */
38      int updatePending;          /* Non-zero when a World Changed event has      int updatePending;          /* Non-zero when a World Changed event has
39                                   * already been queued to handle a change to                                   * already been queued to handle a change to
40                                   * a named font. */                                   * a named font. */
41  } TkFontInfo;  } TkFontInfo;
42    
43  /*  /*
44   * The following data structure is used to keep track of the font attributes   * The following data structure is used to keep track of the font attributes
45   * for each named font that has been defined.  The named font is only deleted   * for each named font that has been defined.  The named font is only deleted
46   * when the last reference to it goes away.   * when the last reference to it goes away.
47   */   */
48    
49  typedef struct NamedFont {  typedef struct NamedFont {
50      int refCount;               /* Number of users of named font. */      int refCount;               /* Number of users of named font. */
51      int deletePending;          /* Non-zero if font should be deleted when      int deletePending;          /* Non-zero if font should be deleted when
52                                   * last reference goes away. */                                   * last reference goes away. */
53      TkFontAttributes fa;        /* Desired attributes for named font. */      TkFontAttributes fa;        /* Desired attributes for named font. */
54  } NamedFont;  } NamedFont;
55            
56  /*  /*
57   * The following two structures are used to keep track of string   * The following two structures are used to keep track of string
58   * measurement information when using the text layout facilities.   * measurement information when using the text layout facilities.
59   *   *
60   * A LayoutChunk represents a contiguous range of text that can be measured   * A LayoutChunk represents a contiguous range of text that can be measured
61   * and displayed by low-level text calls.  In general, chunks will be   * and displayed by low-level text calls.  In general, chunks will be
62   * delimited by newlines and tabs.  Low-level, platform-specific things   * delimited by newlines and tabs.  Low-level, platform-specific things
63   * like kerning and non-integer character widths may occur between the   * like kerning and non-integer character widths may occur between the
64   * characters in a single chunk, but not between characters in different   * characters in a single chunk, but not between characters in different
65   * chunks.   * chunks.
66   *   *
67   * A TextLayout is a collection of LayoutChunks.  It can be displayed with   * A TextLayout is a collection of LayoutChunks.  It can be displayed with
68   * respect to any origin.  It is the implementation of the Tk_TextLayout   * respect to any origin.  It is the implementation of the Tk_TextLayout
69   * opaque token.   * opaque token.
70   */   */
71    
72  typedef struct LayoutChunk {  typedef struct LayoutChunk {
73      CONST char *start;          /* Pointer to simple string to be displayed.      CONST char *start;          /* Pointer to simple string to be displayed.
74                                   * This is a pointer into the TkTextLayout's                                   * This is a pointer into the TkTextLayout's
75                                   * string. */                                   * string. */
76      int numBytes;               /* The number of bytes in this chunk. */      int numBytes;               /* The number of bytes in this chunk. */
77      int numChars;               /* The number of characters in this chunk. */      int numChars;               /* The number of characters in this chunk. */
78      int numDisplayChars;        /* The number of characters to display when      int numDisplayChars;        /* The number of characters to display when
79                                   * this chunk is displayed.  Can be less than                                   * this chunk is displayed.  Can be less than
80                                   * numChars if extra space characters were                                   * numChars if extra space characters were
81                                   * absorbed by the end of the chunk.  This                                   * absorbed by the end of the chunk.  This
82                                   * will be < 0 if this is a chunk that is                                   * will be < 0 if this is a chunk that is
83                                   * holding a tab or newline. */                                   * holding a tab or newline. */
84      int x, y;                   /* The origin of the first character in this      int x, y;                   /* The origin of the first character in this
85                                   * chunk with respect to the upper-left hand                                   * chunk with respect to the upper-left hand
86                                   * corner of the TextLayout. */                                   * corner of the TextLayout. */
87      int totalWidth;             /* Width in pixels of this chunk.  Used      int totalWidth;             /* Width in pixels of this chunk.  Used
88                                   * when hit testing the invisible spaces at                                   * when hit testing the invisible spaces at
89                                   * the end of a chunk. */                                   * the end of a chunk. */
90      int displayWidth;           /* Width in pixels of the displayable      int displayWidth;           /* Width in pixels of the displayable
91                                   * characters in this chunk.  Can be less than                                   * characters in this chunk.  Can be less than
92                                   * width if extra space characters were                                   * width if extra space characters were
93                                   * absorbed by the end of the chunk. */                                   * absorbed by the end of the chunk. */
94  } LayoutChunk;  } LayoutChunk;
95    
96  typedef struct TextLayout {  typedef struct TextLayout {
97      Tk_Font tkfont;             /* The font used when laying out the text. */      Tk_Font tkfont;             /* The font used when laying out the text. */
98      CONST char *string;         /* The string that was layed out. */      CONST char *string;         /* The string that was layed out. */
99      int width;                  /* The maximum width of all lines in the      int width;                  /* The maximum width of all lines in the
100                                   * text layout. */                                   * text layout. */
101      int numChunks;              /* Number of chunks actually used in      int numChunks;              /* Number of chunks actually used in
102                                   * following array. */                                   * following array. */
103      LayoutChunk chunks[1];      /* Array of chunks.  The actual size will      LayoutChunk chunks[1];      /* Array of chunks.  The actual size will
104                                   * be maxChunks.  THIS FIELD MUST BE THE LAST                                   * be maxChunks.  THIS FIELD MUST BE THE LAST
105                                   * IN THE STRUCTURE. */                                   * IN THE STRUCTURE. */
106  } TextLayout;  } TextLayout;
107    
108  /*  /*
109   * The following structures are used as two-way maps between the values for   * The following structures are used as two-way maps between the values for
110   * the fields in the TkFontAttributes structure and the strings used in   * the fields in the TkFontAttributes structure and the strings used in
111   * Tcl, when parsing both option-value format and style-list format font   * Tcl, when parsing both option-value format and style-list format font
112   * name strings.   * name strings.
113   */   */
114    
115  static TkStateMap weightMap[] = {  static TkStateMap weightMap[] = {
116      {TK_FW_NORMAL,      "normal"},      {TK_FW_NORMAL,      "normal"},
117      {TK_FW_BOLD,        "bold"},      {TK_FW_BOLD,        "bold"},
118      {TK_FW_UNKNOWN,     NULL}      {TK_FW_UNKNOWN,     NULL}
119  };  };
120    
121  static TkStateMap slantMap[] = {  static TkStateMap slantMap[] = {
122      {TK_FS_ROMAN,       "roman"},      {TK_FS_ROMAN,       "roman"},
123      {TK_FS_ITALIC,      "italic"},      {TK_FS_ITALIC,      "italic"},
124      {TK_FS_UNKNOWN,     NULL}      {TK_FS_UNKNOWN,     NULL}
125  };  };
126    
127  static TkStateMap underlineMap[] = {  static TkStateMap underlineMap[] = {
128      {1,                 "underline"},      {1,                 "underline"},
129      {0,                 NULL}      {0,                 NULL}
130  };  };
131    
132  static TkStateMap overstrikeMap[] = {  static TkStateMap overstrikeMap[] = {
133      {1,                 "overstrike"},      {1,                 "overstrike"},
134      {0,                 NULL}      {0,                 NULL}
135  };  };
136    
137  /*  /*
138   * The following structures are used when parsing XLFD's into a set of   * The following structures are used when parsing XLFD's into a set of
139   * TkFontAttributes.   * TkFontAttributes.
140   */   */
141    
142  static TkStateMap xlfdWeightMap[] = {  static TkStateMap xlfdWeightMap[] = {
143      {TK_FW_NORMAL,      "normal"},      {TK_FW_NORMAL,      "normal"},
144      {TK_FW_NORMAL,      "medium"},      {TK_FW_NORMAL,      "medium"},
145      {TK_FW_NORMAL,      "book"},      {TK_FW_NORMAL,      "book"},
146      {TK_FW_NORMAL,      "light"},      {TK_FW_NORMAL,      "light"},
147      {TK_FW_BOLD,        "bold"},      {TK_FW_BOLD,        "bold"},
148      {TK_FW_BOLD,        "demi"},      {TK_FW_BOLD,        "demi"},
149      {TK_FW_BOLD,        "demibold"},      {TK_FW_BOLD,        "demibold"},
150      {TK_FW_NORMAL,      NULL}           /* Assume anything else is "normal". */      {TK_FW_NORMAL,      NULL}           /* Assume anything else is "normal". */
151  };  };
152    
153  static TkStateMap xlfdSlantMap[] = {  static TkStateMap xlfdSlantMap[] = {
154      {TK_FS_ROMAN,       "r"},      {TK_FS_ROMAN,       "r"},
155      {TK_FS_ITALIC,      "i"},      {TK_FS_ITALIC,      "i"},
156      {TK_FS_OBLIQUE,     "o"},      {TK_FS_OBLIQUE,     "o"},
157      {TK_FS_ROMAN,       NULL}           /* Assume anything else is "roman". */      {TK_FS_ROMAN,       NULL}           /* Assume anything else is "roman". */
158  };  };
159    
160  static TkStateMap xlfdSetwidthMap[] = {  static TkStateMap xlfdSetwidthMap[] = {
161      {TK_SW_NORMAL,      "normal"},      {TK_SW_NORMAL,      "normal"},
162      {TK_SW_CONDENSE,    "narrow"},      {TK_SW_CONDENSE,    "narrow"},
163      {TK_SW_CONDENSE,    "semicondensed"},      {TK_SW_CONDENSE,    "semicondensed"},
164      {TK_SW_CONDENSE,    "condensed"},      {TK_SW_CONDENSE,    "condensed"},
165      {TK_SW_UNKNOWN,     NULL}      {TK_SW_UNKNOWN,     NULL}
166  };  };
167    
168  /*  /*
169   * The following structure and defines specify the valid builtin options   * The following structure and defines specify the valid builtin options
170   * when configuring a set of font attributes.   * when configuring a set of font attributes.
171   */   */
172    
173  static char *fontOpt[] = {  static char *fontOpt[] = {
174      "-family",      "-family",
175      "-size",      "-size",
176      "-weight",      "-weight",
177      "-slant",      "-slant",
178      "-underline",      "-underline",
179      "-overstrike",      "-overstrike",
180      NULL      NULL
181  };  };
182    
183  #define FONT_FAMILY     0  #define FONT_FAMILY     0
184  #define FONT_SIZE       1  #define FONT_SIZE       1
185  #define FONT_WEIGHT     2  #define FONT_WEIGHT     2
186  #define FONT_SLANT      3  #define FONT_SLANT      3
187  #define FONT_UNDERLINE  4  #define FONT_UNDERLINE  4
188  #define FONT_OVERSTRIKE 5  #define FONT_OVERSTRIKE 5
189  #define FONT_NUMFIELDS  6  #define FONT_NUMFIELDS  6
190    
191  /*  /*
192   * Hardcoded font aliases.  These are used to describe (mostly) identical   * Hardcoded font aliases.  These are used to describe (mostly) identical
193   * fonts whose names differ from platform to platform.  If the   * fonts whose names differ from platform to platform.  If the
194   * user-supplied font name matches any of the names in one of the alias   * user-supplied font name matches any of the names in one of the alias
195   * lists, the other names in the alias list are also automatically tried.   * lists, the other names in the alias list are also automatically tried.
196   */   */
197    
198  static char *timesAliases[] = {  static char *timesAliases[] = {
199      "Times",                    /* Unix. */      "Times",                    /* Unix. */
200      "Times New Roman",          /* Windows. */      "Times New Roman",          /* Windows. */
201      "New York",                 /* Mac. */      "New York",                 /* Mac. */
202      NULL      NULL
203  };  };
204    
205  static char *helveticaAliases[] = {  static char *helveticaAliases[] = {
206      "Helvetica",                /* Unix. */      "Helvetica",                /* Unix. */
207      "Arial",                    /* Windows. */      "Arial",                    /* Windows. */
208      "Geneva",                   /* Mac. */      "Geneva",                   /* Mac. */
209      NULL      NULL
210  };  };
211    
212  static char *courierAliases[] = {  static char *courierAliases[] = {
213      "Courier",                  /* Unix and Mac. */      "Courier",                  /* Unix and Mac. */
214      "Courier New",              /* Windows. */      "Courier New",              /* Windows. */
215      NULL      NULL
216  };  };
217    
218  static char *minchoAliases[] = {  static char *minchoAliases[] = {
219      "mincho",                   /* Unix. */      "mincho",                   /* Unix. */
220      "\357\274\255\357\274\263 \346\230\216\346\234\235",      "\357\274\255\357\274\263 \346\230\216\346\234\235",
221                                  /* Windows (MS mincho). */                                  /* Windows (MS mincho). */
222      "\346\234\254\346\230\216\346\234\235\342\210\222\357\274\255",      "\346\234\254\346\230\216\346\234\235\342\210\222\357\274\255",
223                                  /* Mac (honmincho-M). */                                  /* Mac (honmincho-M). */
224      NULL      NULL
225  };  };
226    
227  static char *gothicAliases[] = {  static char *gothicAliases[] = {
228      "gothic",                   /* Unix. */      "gothic",                   /* Unix. */
229      "\357\274\255\357\274\263 \343\202\264\343\202\267\343\203\203\343\202\257",      "\357\274\255\357\274\263 \343\202\264\343\202\267\343\203\203\343\202\257",
230                                  /* Windows (MS goshikku). */                                  /* Windows (MS goshikku). */
231      "\344\270\270\343\202\264\343\202\267\343\203\203\343\202\257\342\210\222\357\274\255",      "\344\270\270\343\202\264\343\202\267\343\203\203\343\202\257\342\210\222\357\274\255",
232                                  /* Mac (goshikku-M). */                                  /* Mac (goshikku-M). */
233      NULL          NULL    
234  };  };
235    
236  static char *dingbatsAliases[] = {  static char *dingbatsAliases[] = {
237      "dingbats", "zapfdingbats", "itc zapfdingbats",      "dingbats", "zapfdingbats", "itc zapfdingbats",
238                                  /* Unix. */                                  /* Unix. */
239                                  /* Windows. */                                  /* Windows. */
240      "zapf dingbats",            /* Mac. */      "zapf dingbats",            /* Mac. */
241      NULL      NULL
242  };  };
243    
244  static char **fontAliases[] = {  static char **fontAliases[] = {
245      timesAliases,      timesAliases,
246      helveticaAliases,      helveticaAliases,
247      courierAliases,      courierAliases,
248      minchoAliases,      minchoAliases,
249      gothicAliases,      gothicAliases,
250      dingbatsAliases,      dingbatsAliases,
251      NULL      NULL
252  };    };  
253    
254  /*  /*
255   * Hardcoded font classes.  If the character cannot be found in the base   * Hardcoded font classes.  If the character cannot be found in the base
256   * font, the classes are examined in order to see if some other similar   * font, the classes are examined in order to see if some other similar
257   * font should be examined also.     * font should be examined also.  
258   */   */
259    
260  static char *systemClass[] = {  static char *systemClass[] = {
261      "fixed",                            /* Unix. */      "fixed",                            /* Unix. */
262                                          /* Windows. */                                          /* Windows. */
263      "chicago", "osaka", "sistemny",     /* Mac. */      "chicago", "osaka", "sistemny",     /* Mac. */
264      NULL      NULL
265  };  };
266    
267  static char *serifClass[] = {  static char *serifClass[] = {
268      "times", "palatino", "mincho",      /* All platforms. */      "times", "palatino", "mincho",      /* All platforms. */
269      "song ti",                          /* Unix. */      "song ti",                          /* Unix. */
270      "ms serif", "simplified arabic",    /* Windows. */      "ms serif", "simplified arabic",    /* Windows. */
271      "latinski",                         /* Mac. */      "latinski",                         /* Mac. */
272      NULL      NULL
273  };  };
274    
275  static char *sansClass[] = {  static char *sansClass[] = {
276      "helvetica", "gothic",              /* All platforms. */      "helvetica", "gothic",              /* All platforms. */
277                                          /* Unix. */                                          /* Unix. */
278      "ms sans serif", "traditional arabic",      "ms sans serif", "traditional arabic",
279                                          /* Windows. */                                          /* Windows. */
280      "bastion",                          /* Mac. */      "bastion",                          /* Mac. */
281      NULL      NULL
282  };  };
283    
284  static char *monoClass[] = {  static char *monoClass[] = {
285      "courier", "gothic",                /* All platforms. */      "courier", "gothic",                /* All platforms. */
286      "fangsong ti",                      /* Unix. */      "fangsong ti",                      /* Unix. */
287      "simplified arabic fixed",          /* Windows. */      "simplified arabic fixed",          /* Windows. */
288      "monaco", "pryamoy",                /* Mac. */      "monaco", "pryamoy",                /* Mac. */
289      NULL      NULL
290  };  };
291    
292  static char *symbolClass[] = {  static char *symbolClass[] = {
293      "symbol", "dingbats", "wingdings", NULL      "symbol", "dingbats", "wingdings", NULL
294  };  };
295    
296  static char **fontFallbacks[] = {  static char **fontFallbacks[] = {
297      systemClass,      systemClass,
298      serifClass,      serifClass,
299      sansClass,      sansClass,
300      monoClass,      monoClass,
301      symbolClass,      symbolClass,
302      NULL      NULL
303  };  };
304    
305  /*  /*
306   * Global fallbacks.  If the character could not be found in the preferred   * Global fallbacks.  If the character could not be found in the preferred
307   * fallback list, this list is examined.  If the character still cannot be   * fallback list, this list is examined.  If the character still cannot be
308   * found, all font families in the system are examined.   * found, all font families in the system are examined.
309   */   */
310    
311  static char *globalFontClass[] = {  static char *globalFontClass[] = {
312      "symbol",                   /* All platforms. */      "symbol",                   /* All platforms. */
313                                  /* Unix. */                                  /* Unix. */
314      "lucida sans unicode",      /* Windows. */      "lucida sans unicode",      /* Windows. */
315      "bitstream cyberbit",       /* Windows popular CJK font */      "bitstream cyberbit",       /* Windows popular CJK font */
316      "chicago",                  /* Mac. */      "chicago",                  /* Mac. */
317      NULL      NULL
318  };  };
319    
320  #define GetFontAttributes(tkfont) \  #define GetFontAttributes(tkfont) \
321                  ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa)                  ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa)
322    
323  #define GetFontMetrics(tkfont)    \  #define GetFontMetrics(tkfont)    \
324                  ((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm)                  ((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm)
325    
326    
327  static int              ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp,  static int              ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp,
328                              Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[],                              Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[],
329                              TkFontAttributes *faPtr));                              TkFontAttributes *faPtr));
330  static int              CreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp,  static int              CreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp,
331                              Tk_Window tkwin, CONST char *name,                              Tk_Window tkwin, CONST char *name,
332                              TkFontAttributes *faPtr));                              TkFontAttributes *faPtr));
333  static void             DupFontObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,  static void             DupFontObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
334                              Tcl_Obj *dupObjPtr));                              Tcl_Obj *dupObjPtr));
335  static int              FieldSpecified _ANSI_ARGS_((CONST char *field));  static int              FieldSpecified _ANSI_ARGS_((CONST char *field));
336  static void             FreeFontObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));  static void             FreeFontObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
337  static int              GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp,  static int              GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp,
338                              CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr));                              CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr));
339  static LayoutChunk *    NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr,  static LayoutChunk *    NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr,
340                              int *maxPtr, CONST char *start, int numChars,                              int *maxPtr, CONST char *start, int numChars,
341                              int curX, int newX, int y));                              int curX, int newX, int y));
342  static int              ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp,  static int              ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp,
343                              Tk_Window tkwin, Tcl_Obj *objPtr,                              Tk_Window tkwin, Tcl_Obj *objPtr,
344                              TkFontAttributes *faPtr));                              TkFontAttributes *faPtr));
345  static void             RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr));  static void             RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr));
346  static int              SetFontFromAny _ANSI_ARGS_((Tcl_Interp *interp,  static int              SetFontFromAny _ANSI_ARGS_((Tcl_Interp *interp,
347                              Tcl_Obj *objPtr));                              Tcl_Obj *objPtr));
348  static void             TheWorldHasChanged _ANSI_ARGS_((  static void             TheWorldHasChanged _ANSI_ARGS_((
349                              ClientData clientData));                              ClientData clientData));
350  static void             UpdateDependentFonts _ANSI_ARGS_((TkFontInfo *fiPtr,  static void             UpdateDependentFonts _ANSI_ARGS_((TkFontInfo *fiPtr,
351                              Tk_Window tkwin, Tcl_HashEntry *namedHashPtr));                              Tk_Window tkwin, Tcl_HashEntry *namedHashPtr));
352    
353  /*  /*
354   * The following structure defines the implementation of the "font" Tcl   * The following structure defines the implementation of the "font" Tcl
355   * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of   * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of
356   * each font object points to the TkFont structure for the font, or   * each font object points to the TkFont structure for the font, or
357   * NULL.   * NULL.
358   */   */
359    
360  static Tcl_ObjType fontObjType = {  static Tcl_ObjType fontObjType = {
361      "font",                     /* name */      "font",                     /* name */
362      FreeFontObjProc,            /* freeIntRepProc */      FreeFontObjProc,            /* freeIntRepProc */
363      DupFontObjProc,             /* dupIntRepProc */      DupFontObjProc,             /* dupIntRepProc */
364      NULL,                       /* updateStringProc */      NULL,                       /* updateStringProc */
365      SetFontFromAny              /* setFromAnyProc */      SetFontFromAny              /* setFromAnyProc */
366  };  };
367    
368    
369  /*  /*
370   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
371   *   *
372   * TkFontPkgInit --   * TkFontPkgInit --
373   *   *
374   *      This procedure is called when an application is created.  It   *      This procedure is called when an application is created.  It
375   *      initializes all the structures that are used by the font   *      initializes all the structures that are used by the font
376   *      package on a per application basis.   *      package on a per application basis.
377   *   *
378   * Results:   * Results:
379   *      Stores a token in the mainPtr to hold information needed by this   *      Stores a token in the mainPtr to hold information needed by this
380   *      package on a per application basis.   *      package on a per application basis.
381   *   *
382   * Side effects:   * Side effects:
383   *      Memory allocated.   *      Memory allocated.
384   *   *
385   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
386   */   */
387  void  void
388  TkFontPkgInit(mainPtr)  TkFontPkgInit(mainPtr)
389      TkMainInfo *mainPtr;        /* The application being created. */      TkMainInfo *mainPtr;        /* The application being created. */
390  {  {
391      TkFontInfo *fiPtr;      TkFontInfo *fiPtr;
392    
393      fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo));      fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo));
394      Tcl_InitHashTable(&fiPtr->fontCache, TCL_STRING_KEYS);      Tcl_InitHashTable(&fiPtr->fontCache, TCL_STRING_KEYS);
395      Tcl_InitHashTable(&fiPtr->namedTable, TCL_STRING_KEYS);      Tcl_InitHashTable(&fiPtr->namedTable, TCL_STRING_KEYS);
396      fiPtr->mainPtr = mainPtr;      fiPtr->mainPtr = mainPtr;
397      fiPtr->updatePending = 0;      fiPtr->updatePending = 0;
398      mainPtr->fontInfoPtr = fiPtr;      mainPtr->fontInfoPtr = fiPtr;
399    
400      TkpFontPkgInit(mainPtr);      TkpFontPkgInit(mainPtr);
401  }  }
402    
403  /*  /*
404   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
405   *   *
406   * TkFontPkgFree --   * TkFontPkgFree --
407   *   *
408   *      This procedure is called when an application is deleted.  It   *      This procedure is called when an application is deleted.  It
409   *      deletes all the structures that were used by the font package   *      deletes all the structures that were used by the font package
410   *      for this application.   *      for this application.
411   *   *
412   * Results:   * Results:
413   *      None.   *      None.
414   *   *
415   * Side effects:   * Side effects:
416   *      Memory freed.   *      Memory freed.
417   *   *
418   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
419   */   */
420    
421  void  void
422  TkFontPkgFree(mainPtr)  TkFontPkgFree(mainPtr)
423      TkMainInfo *mainPtr;        /* The application being deleted. */      TkMainInfo *mainPtr;        /* The application being deleted. */
424  {  {
425      TkFontInfo *fiPtr;      TkFontInfo *fiPtr;
426      Tcl_HashEntry *hPtr, *searchPtr;      Tcl_HashEntry *hPtr, *searchPtr;
427      Tcl_HashSearch search;      Tcl_HashSearch search;
428      int fontsLeft;      int fontsLeft;
429    
430      fiPtr = mainPtr->fontInfoPtr;      fiPtr = mainPtr->fontInfoPtr;
431    
432      fontsLeft = 0;      fontsLeft = 0;
433      for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);      for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
434              searchPtr != NULL;              searchPtr != NULL;
435              searchPtr = Tcl_NextHashEntry(&search)) {              searchPtr = Tcl_NextHashEntry(&search)) {
436          fontsLeft++;          fontsLeft++;
437          fprintf(stderr, "Font %s still in cache.\n",          fprintf(stderr, "Font %s still in cache.\n",
438                  Tcl_GetHashKey(&fiPtr->fontCache, searchPtr));                  Tcl_GetHashKey(&fiPtr->fontCache, searchPtr));
439      }      }
440      if (fontsLeft) {      if (fontsLeft) {
441          panic("TkFontPkgFree: all fonts should have been freed already");          panic("TkFontPkgFree: all fonts should have been freed already");
442      }      }
443      Tcl_DeleteHashTable(&fiPtr->fontCache);      Tcl_DeleteHashTable(&fiPtr->fontCache);
444    
445      hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);      hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
446      while (hPtr != NULL) {      while (hPtr != NULL) {
447          ckfree((char *) Tcl_GetHashValue(hPtr));          ckfree((char *) Tcl_GetHashValue(hPtr));
448          hPtr = Tcl_NextHashEntry(&search);          hPtr = Tcl_NextHashEntry(&search);
449      }      }
450      Tcl_DeleteHashTable(&fiPtr->namedTable);      Tcl_DeleteHashTable(&fiPtr->namedTable);
451      if (fiPtr->updatePending != 0) {      if (fiPtr->updatePending != 0) {
452          Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr);          Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr);
453      }      }
454      ckfree((char *) fiPtr);      ckfree((char *) fiPtr);
455  }  }
456    
457  /*  /*
458   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
459   *   *
460   * Tk_FontObjCmd --   * Tk_FontObjCmd --
461   *   *
462   *      This procedure is implemented to process the "font" Tcl command.   *      This procedure is implemented to process the "font" Tcl command.
463   *      See the user documentation for details on what it does.   *      See the user documentation for details on what it does.
464   *   *
465   * Results:   * Results:
466   *      A standard Tcl result.   *      A standard Tcl result.
467   *   *
468   * Side effects:   * Side effects:
469   *      See the user documentation.   *      See the user documentation.
470   *   *
471   *----------------------------------------------------------------------   *----------------------------------------------------------------------
472   */   */
473    
474  int  int
475  Tk_FontObjCmd(clientData, interp, objc, objv)  Tk_FontObjCmd(clientData, interp, objc, objv)
476      ClientData clientData;      /* Main window associated with interpreter. */      ClientData clientData;      /* Main window associated with interpreter. */
477      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
478      int objc;                   /* Number of arguments. */      int objc;                   /* Number of arguments. */
479      Tcl_Obj *CONST objv[];      /* Argument objects. */      Tcl_Obj *CONST objv[];      /* Argument objects. */
480  {  {
481      int index;      int index;
482      Tk_Window tkwin;      Tk_Window tkwin;
483      TkFontInfo *fiPtr;      TkFontInfo *fiPtr;
484      static char *optionStrings[] = {      static char *optionStrings[] = {
485          "actual",       "configure",    "create",       "delete",          "actual",       "configure",    "create",       "delete",
486          "families",     "measure",      "metrics",      "names",          "families",     "measure",      "metrics",      "names",
487          NULL          NULL
488      };      };
489      enum options {      enum options {
490          FONT_ACTUAL,    FONT_CONFIGURE, FONT_CREATE,    FONT_DELETE,          FONT_ACTUAL,    FONT_CONFIGURE, FONT_CREATE,    FONT_DELETE,
491          FONT_FAMILIES,  FONT_MEASURE,   FONT_METRICS,   FONT_NAMES          FONT_FAMILIES,  FONT_MEASURE,   FONT_METRICS,   FONT_NAMES
492      };      };
493    
494      tkwin = (Tk_Window) clientData;      tkwin = (Tk_Window) clientData;
495      fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;      fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
496    
497      if (objc < 2) {      if (objc < 2) {
498          Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");          Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
499          return TCL_ERROR;          return TCL_ERROR;
500      }      }
501      if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,      if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
502              &index) != TCL_OK) {              &index) != TCL_OK) {
503          return TCL_ERROR;          return TCL_ERROR;
504      }      }
505    
506      switch ((enum options) index) {      switch ((enum options) index) {
507          case FONT_ACTUAL: {          case FONT_ACTUAL: {
508              int skip, result;              int skip, result;
509              Tk_Font tkfont;              Tk_Font tkfont;
510              Tcl_Obj *objPtr;              Tcl_Obj *objPtr;
511              CONST TkFontAttributes *faPtr;              CONST TkFontAttributes *faPtr;
512    
513              skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);              skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
514              if (skip < 0) {              if (skip < 0) {
515                  return TCL_ERROR;                  return TCL_ERROR;
516              }              }
517              if ((objc < 3) || (objc - skip > 4)) {              if ((objc < 3) || (objc - skip > 4)) {
518                  Tcl_WrongNumArgs(interp, 2, objv,                  Tcl_WrongNumArgs(interp, 2, objv,
519                          "font ?-displayof window? ?option?");                          "font ?-displayof window? ?option?");
520                  return TCL_ERROR;                  return TCL_ERROR;
521              }              }
522              tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);              tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
523              if (tkfont == NULL) {              if (tkfont == NULL) {
524                  return TCL_ERROR;                  return TCL_ERROR;
525              }              }
526              objc -= skip;              objc -= skip;
527              objv += skip;              objv += skip;
528              faPtr = GetFontAttributes(tkfont);              faPtr = GetFontAttributes(tkfont);
529              objPtr = NULL;              objPtr = NULL;
530              if (objc > 3) {              if (objc > 3) {
531                  objPtr = objv[3];                  objPtr = objv[3];
532              }              }
533              result = GetAttributeInfoObj(interp, faPtr, objPtr);              result = GetAttributeInfoObj(interp, faPtr, objPtr);
534              Tk_FreeFont(tkfont);              Tk_FreeFont(tkfont);
535              return result;              return result;
536          }          }
537          case FONT_CONFIGURE: {          case FONT_CONFIGURE: {
538              int result;              int result;
539              char *string;              char *string;
540              Tcl_Obj *objPtr;              Tcl_Obj *objPtr;
541              NamedFont *nfPtr;              NamedFont *nfPtr;
542              Tcl_HashEntry *namedHashPtr;              Tcl_HashEntry *namedHashPtr;
543    
544              if (objc < 3) {              if (objc < 3) {
545                  Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?");                  Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?");
546                  return TCL_ERROR;                  return TCL_ERROR;
547              }              }
548              string = Tcl_GetString(objv[2]);              string = Tcl_GetString(objv[2]);
549              namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);              namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
550              nfPtr = NULL;               /* lint. */              nfPtr = NULL;               /* lint. */
551              if (namedHashPtr != NULL) {              if (namedHashPtr != NULL) {
552                  nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);                  nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
553              }              }
554              if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) {              if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) {
555                  Tcl_AppendResult(interp, "named font \"", string,                  Tcl_AppendResult(interp, "named font \"", string,
556                          "\" doesn't exist", NULL);                          "\" doesn't exist", NULL);
557                  return TCL_ERROR;                  return TCL_ERROR;
558              }              }
559              if (objc == 3) {              if (objc == 3) {
560                  objPtr = NULL;                  objPtr = NULL;
561              } else if (objc == 4) {              } else if (objc == 4) {
562                  objPtr = objv[3];                  objPtr = objv[3];
563              } else {              } else {
564                  result = ConfigAttributesObj(interp, tkwin, objc - 3,                  result = ConfigAttributesObj(interp, tkwin, objc - 3,
565                          objv + 3, &nfPtr->fa);                          objv + 3, &nfPtr->fa);
566                  UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);                  UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);
567                  return result;                  return result;
568              }              }
569              return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr);              return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr);
570          }          }
571          case FONT_CREATE: {          case FONT_CREATE: {
572              int skip, i;              int skip, i;
573              char *name;              char *name;
574              char buf[16 + TCL_INTEGER_SPACE];              char buf[16 + TCL_INTEGER_SPACE];
575              TkFontAttributes fa;              TkFontAttributes fa;
576              Tcl_HashEntry *namedHashPtr;              Tcl_HashEntry *namedHashPtr;
577    
578              skip = 3;              skip = 3;
579              if (objc < 3) {              if (objc < 3) {
580                  name = NULL;                  name = NULL;
581              } else {              } else {
582                  name = Tcl_GetString(objv[2]);                  name = Tcl_GetString(objv[2]);
583                  if (name[0] == '-') {                  if (name[0] == '-') {
584                      name = NULL;                      name = NULL;
585                  }                  }
586              }              }
587              if (name == NULL) {              if (name == NULL) {
588                  /*                  /*
589                   * No font name specified.  Generate one of the form "fontX".                   * No font name specified.  Generate one of the form "fontX".
590                   */                   */
591    
592                  for (i = 1; ; i++) {                  for (i = 1; ; i++) {
593                      sprintf(buf, "font%d", i);                      sprintf(buf, "font%d", i);
594                      namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, buf);                      namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, buf);
595                      if (namedHashPtr == NULL) {                      if (namedHashPtr == NULL) {
596                          break;                          break;
597                      }                      }
598                  }                  }
599                  name = buf;                  name = buf;
600                  skip = 2;                  skip = 2;
601              }              }
602              TkInitFontAttributes(&fa);              TkInitFontAttributes(&fa);
603              if (ConfigAttributesObj(interp, tkwin, objc - skip, objv + skip,              if (ConfigAttributesObj(interp, tkwin, objc - skip, objv + skip,
604                      &fa) != TCL_OK) {                      &fa) != TCL_OK) {
605                  return TCL_ERROR;                  return TCL_ERROR;
606              }              }
607              if (CreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) {              if (CreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) {
608                  return TCL_ERROR;                  return TCL_ERROR;
609              }              }
610              Tcl_AppendResult(interp, name, NULL);              Tcl_AppendResult(interp, name, NULL);
611              break;              break;
612          }          }
613          case FONT_DELETE: {          case FONT_DELETE: {
614              int i;              int i;
615              char *string;              char *string;
616              NamedFont *nfPtr;              NamedFont *nfPtr;
617              Tcl_HashEntry *namedHashPtr;              Tcl_HashEntry *namedHashPtr;
618    
619              /*              /*
620               * Delete the named font.  If there are still widgets using this               * Delete the named font.  If there are still widgets using this
621               * font, then it isn't deleted right away.               * font, then it isn't deleted right away.
622               */               */
623    
624              if (objc < 3) {              if (objc < 3) {
625                  Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?");                  Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?");
626                  return TCL_ERROR;                  return TCL_ERROR;
627              }              }
628              for (i = 2; i < objc; i++) {              for (i = 2; i < objc; i++) {
629                  string = Tcl_GetString(objv[i]);                  string = Tcl_GetString(objv[i]);
630                  namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);                  namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
631                  if (namedHashPtr == NULL) {                  if (namedHashPtr == NULL) {
632                      Tcl_AppendResult(interp, "named font \"", string,                      Tcl_AppendResult(interp, "named font \"", string,
633                              "\" doesn't exist", (char *) NULL);                              "\" doesn't exist", (char *) NULL);
634                      return TCL_ERROR;                      return TCL_ERROR;
635                  }                  }
636                  nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);                  nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
637                  if (nfPtr->refCount != 0) {                  if (nfPtr->refCount != 0) {
638                      nfPtr->deletePending = 1;                      nfPtr->deletePending = 1;
639                  } else {                  } else {
640                      Tcl_DeleteHashEntry(namedHashPtr);                      Tcl_DeleteHashEntry(namedHashPtr);
641                      ckfree((char *) nfPtr);                      ckfree((char *) nfPtr);
642                  }                  }
643              }              }
644              break;              break;
645          }          }
646          case FONT_FAMILIES: {          case FONT_FAMILIES: {
647              int skip;              int skip;
648    
649              skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);              skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
650              if (skip < 0) {              if (skip < 0) {
651                  return TCL_ERROR;                  return TCL_ERROR;
652              }              }
653              if (objc - skip != 2) {              if (objc - skip != 2) {
654                  Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?");                  Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?");
655                  return TCL_ERROR;                  return TCL_ERROR;
656              }              }
657              TkpGetFontFamilies(interp, tkwin);              TkpGetFontFamilies(interp, tkwin);
658              break;              break;
659          }          }
660          case FONT_MEASURE: {          case FONT_MEASURE: {
661              char *string;              char *string;
662              Tk_Font tkfont;              Tk_Font tkfont;
663              int length, skip;              int length, skip;
664              Tcl_Obj *resultPtr;              Tcl_Obj *resultPtr;
665                            
666              skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);              skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
667              if (skip < 0) {              if (skip < 0) {
668                  return TCL_ERROR;                  return TCL_ERROR;
669              }              }
670              if (objc - skip != 4) {              if (objc - skip != 4) {
671                  Tcl_WrongNumArgs(interp, 2, objv,                  Tcl_WrongNumArgs(interp, 2, objv,
672                          "font ?-displayof window? text");                          "font ?-displayof window? text");
673                  return TCL_ERROR;                  return TCL_ERROR;
674              }              }
675              tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);              tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
676              if (tkfont == NULL) {              if (tkfont == NULL) {
677                  return TCL_ERROR;                  return TCL_ERROR;
678              }              }
679              string = Tcl_GetStringFromObj(objv[3 + skip], &length);              string = Tcl_GetStringFromObj(objv[3 + skip], &length);
680              resultPtr = Tcl_GetObjResult(interp);              resultPtr = Tcl_GetObjResult(interp);
681              Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length));              Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length));
682              Tk_FreeFont(tkfont);              Tk_FreeFont(tkfont);
683              break;              break;
684          }          }
685          case FONT_METRICS: {          case FONT_METRICS: {
686              Tk_Font tkfont;              Tk_Font tkfont;
687              int skip, index, i;              int skip, index, i;
688              CONST TkFontMetrics *fmPtr;              CONST TkFontMetrics *fmPtr;
689              static char *switches[] = {              static char *switches[] = {
690                  "-ascent", "-descent", "-linespace", "-fixed", NULL                  "-ascent", "-descent", "-linespace", "-fixed", NULL
691              };              };
692    
693              skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);              skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
694              if (skip < 0) {              if (skip < 0) {
695                  return TCL_ERROR;                  return TCL_ERROR;
696              }              }
697              if ((objc < 3) || ((objc - skip) > 4)) {              if ((objc < 3) || ((objc - skip) > 4)) {
698                  Tcl_WrongNumArgs(interp, 2, objv,                  Tcl_WrongNumArgs(interp, 2, objv,
699                          "font ?-displayof window? ?option?");                          "font ?-displayof window? ?option?");
700                  return TCL_ERROR;                  return TCL_ERROR;
701              }              }
702              tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);              tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
703              if (tkfont == NULL) {              if (tkfont == NULL) {
704                  return TCL_ERROR;                  return TCL_ERROR;
705              }              }
706              objc -= skip;              objc -= skip;
707              objv += skip;              objv += skip;
708              fmPtr = GetFontMetrics(tkfont);              fmPtr = GetFontMetrics(tkfont);
709              if (objc == 3) {              if (objc == 3) {
710                  char buf[64 + TCL_INTEGER_SPACE * 4];                  char buf[64 + TCL_INTEGER_SPACE * 4];
711    
712                  sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d",                  sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d",
713                          fmPtr->ascent, fmPtr->descent,                          fmPtr->ascent, fmPtr->descent,
714                          fmPtr->ascent + fmPtr->descent,                          fmPtr->ascent + fmPtr->descent,
715                          fmPtr->fixed);                          fmPtr->fixed);
716                  Tcl_AppendResult(interp, buf, NULL);                  Tcl_AppendResult(interp, buf, NULL);
717              } else {              } else {
718                  if (Tcl_GetIndexFromObj(interp, objv[3], switches,                  if (Tcl_GetIndexFromObj(interp, objv[3], switches,
719                          "metric", 0, &index) != TCL_OK) {                          "metric", 0, &index) != TCL_OK) {
720                      Tk_FreeFont(tkfont);                      Tk_FreeFont(tkfont);
721                      return TCL_ERROR;                      return TCL_ERROR;
722                  }                  }
723                  i = 0;                  /* Needed only to prevent compiler                  i = 0;                  /* Needed only to prevent compiler
724                                           * warning. */                                           * warning. */
725                  switch (index) {                  switch (index) {
726                      case 0: i = fmPtr->ascent;                  break;                      case 0: i = fmPtr->ascent;                  break;
727                      case 1: i = fmPtr->descent;                 break;                      case 1: i = fmPtr->descent;                 break;
728                      case 2: i = fmPtr->ascent + fmPtr->descent; break;                      case 2: i = fmPtr->ascent + fmPtr->descent; break;
729                      case 3: i = fmPtr->fixed;                   break;                      case 3: i = fmPtr->fixed;                   break;
730                  }                  }
731                  Tcl_SetIntObj(Tcl_GetObjResult(interp), i);                  Tcl_SetIntObj(Tcl_GetObjResult(interp), i);
732              }              }
733              Tk_FreeFont(tkfont);              Tk_FreeFont(tkfont);
734              break;              break;
735          }          }
736          case FONT_NAMES: {          case FONT_NAMES: {
737              char *string;              char *string;
738              NamedFont *nfPtr;              NamedFont *nfPtr;
739              Tcl_HashSearch search;              Tcl_HashSearch search;
740              Tcl_HashEntry *namedHashPtr;              Tcl_HashEntry *namedHashPtr;
741              Tcl_Obj *strPtr, *resultPtr;              Tcl_Obj *strPtr, *resultPtr;
742                            
743              if (objc != 2) {              if (objc != 2) {
744                  Tcl_WrongNumArgs(interp, 1, objv, "names");                  Tcl_WrongNumArgs(interp, 1, objv, "names");
745                  return TCL_ERROR;                  return TCL_ERROR;
746              }              }
747              resultPtr = Tcl_GetObjResult(interp);              resultPtr = Tcl_GetObjResult(interp);
748              namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);              namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
749              while (namedHashPtr != NULL) {              while (namedHashPtr != NULL) {
750                  nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);                  nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
751                  if (nfPtr->deletePending == 0) {                  if (nfPtr->deletePending == 0) {
752                      string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr);                      string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr);
753                      strPtr = Tcl_NewStringObj(string, -1);                      strPtr = Tcl_NewStringObj(string, -1);
754                      Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);                      Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
755                  }                  }
756                  namedHashPtr = Tcl_NextHashEntry(&search);                  namedHashPtr = Tcl_NextHashEntry(&search);
757              }              }
758              break;              break;
759          }          }
760      }      }
761      return TCL_OK;      return TCL_OK;
762  }  }
763    
764  /*  /*
765   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
766   *   *
767   * UpdateDependentFonts, TheWorldHasChanged, RecomputeWidgets --   * UpdateDependentFonts, TheWorldHasChanged, RecomputeWidgets --
768   *   *
769   *      Called when the attributes of a named font changes.  Updates all   *      Called when the attributes of a named font changes.  Updates all
770   *      the instantiated fonts that depend on that named font and then   *      the instantiated fonts that depend on that named font and then
771   *      uses the brute force approach and prepares every widget to   *      uses the brute force approach and prepares every widget to
772   *      recompute its geometry.   *      recompute its geometry.
773   *   *
774   * Results:   * Results:
775   *      None.   *      None.
776   *   *
777   * Side effects:   * Side effects:
778   *      Things get queued for redisplay.   *      Things get queued for redisplay.
779   *   *
780   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
781   */   */
782    
783  static void  static void
784  UpdateDependentFonts(fiPtr, tkwin, namedHashPtr)  UpdateDependentFonts(fiPtr, tkwin, namedHashPtr)
785      TkFontInfo *fiPtr;          /* Info about application's fonts. */      TkFontInfo *fiPtr;          /* Info about application's fonts. */
786      Tk_Window tkwin;            /* A window in the application. */      Tk_Window tkwin;            /* A window in the application. */
787      Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */      Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */
788  {  {
789      Tcl_HashEntry *cacheHashPtr;      Tcl_HashEntry *cacheHashPtr;
790      Tcl_HashSearch search;      Tcl_HashSearch search;
791      TkFont *fontPtr;      TkFont *fontPtr;
792      NamedFont *nfPtr;      NamedFont *nfPtr;
793    
794      nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);      nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
795      if (nfPtr->refCount == 0) {      if (nfPtr->refCount == 0) {
796          /*          /*
797           * Well nobody's using this named font, so don't have to tell           * Well nobody's using this named font, so don't have to tell
798           * any widgets to recompute themselves.           * any widgets to recompute themselves.
799           */           */
800    
801          return;          return;
802      }      }
803    
804      cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);      cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
805      while (cacheHashPtr != NULL) {      while (cacheHashPtr != NULL) {
806          for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);          for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
807                  fontPtr != NULL; fontPtr = fontPtr->nextPtr) {                  fontPtr != NULL; fontPtr = fontPtr->nextPtr) {
808              if (fontPtr->namedHashPtr == namedHashPtr) {              if (fontPtr->namedHashPtr == namedHashPtr) {
809                  TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa);                  TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa);
810                  if (fiPtr->updatePending == 0) {                  if (fiPtr->updatePending == 0) {
811                      fiPtr->updatePending = 1;                      fiPtr->updatePending = 1;
812                      Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr);                      Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr);
813                  }                  }
814              }              }
815          }          }
816          cacheHashPtr = Tcl_NextHashEntry(&search);          cacheHashPtr = Tcl_NextHashEntry(&search);
817      }      }
818  }  }
819    
820  static void  static void
821  TheWorldHasChanged(clientData)  TheWorldHasChanged(clientData)
822      ClientData clientData;      /* Info about application's fonts. */      ClientData clientData;      /* Info about application's fonts. */
823  {  {
824      TkFontInfo *fiPtr;      TkFontInfo *fiPtr;
825    
826      fiPtr = (TkFontInfo *) clientData;      fiPtr = (TkFontInfo *) clientData;
827      fiPtr->updatePending = 0;      fiPtr->updatePending = 0;
828    
829      RecomputeWidgets(fiPtr->mainPtr->winPtr);      RecomputeWidgets(fiPtr->mainPtr->winPtr);
830  }  }
831    
832  static void  static void
833  RecomputeWidgets(winPtr)  RecomputeWidgets(winPtr)
834      TkWindow *winPtr;           /* Window to which command is sent. */      TkWindow *winPtr;           /* Window to which command is sent. */
835  {  {
836      if ((winPtr->classProcsPtr != NULL)      if ((winPtr->classProcsPtr != NULL)
837              && (winPtr->classProcsPtr->geometryProc != NULL)) {              && (winPtr->classProcsPtr->geometryProc != NULL)) {
838          (*winPtr->classProcsPtr->geometryProc)(winPtr->instanceData);          (*winPtr->classProcsPtr->geometryProc)(winPtr->instanceData);
839      }      }
840      for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) {      for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) {
841          RecomputeWidgets(winPtr);          RecomputeWidgets(winPtr);
842      }      }
843  }  }
844    
845  /*  /*
846   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
847   *   *
848   * CreateNamedFont --   * CreateNamedFont --
849   *   *
850   *      Create the specified named font with the given attributes in the   *      Create the specified named font with the given attributes in the
851   *      named font table associated with the interp.     *      named font table associated with the interp.  
852   *   *
853   * Results:   * Results:
854   *      Returns TCL_OK if the font was successfully created, or TCL_ERROR   *      Returns TCL_OK if the font was successfully created, or TCL_ERROR
855   *      if the named font already existed.  If TCL_ERROR is returned, an   *      if the named font already existed.  If TCL_ERROR is returned, an
856   *      error message is left in the interp's result.   *      error message is left in the interp's result.
857   *   *
858   * Side effects:   * Side effects:
859   *      Assume there used to exist a named font by the specified name, and   *      Assume there used to exist a named font by the specified name, and
860   *      that the named font had been deleted, but there were still some   *      that the named font had been deleted, but there were still some
861   *      widgets using the named font at the time it was deleted.  If a   *      widgets using the named font at the time it was deleted.  If a
862   *      new named font is created with the same name, all those widgets   *      new named font is created with the same name, all those widgets
863   *      that were using the old named font will be redisplayed using   *      that were using the old named font will be redisplayed using
864   *      the new named font's attributes.   *      the new named font's attributes.
865   *   *
866   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
867   */   */
868    
869  static int  static int
870  CreateNamedFont(interp, tkwin, name, faPtr)  CreateNamedFont(interp, tkwin, name, faPtr)
871      Tcl_Interp *interp;         /* Interp for error return. */      Tcl_Interp *interp;         /* Interp for error return. */
872      Tk_Window tkwin;            /* A window associated with interp. */      Tk_Window tkwin;            /* A window associated with interp. */
873      CONST char *name;           /* Name for the new named font. */      CONST char *name;           /* Name for the new named font. */
874      TkFontAttributes *faPtr;    /* Attributes for the new named font. */      TkFontAttributes *faPtr;    /* Attributes for the new named font. */
875  {  {
876      TkFontInfo *fiPtr;      TkFontInfo *fiPtr;
877      Tcl_HashEntry *namedHashPtr;      Tcl_HashEntry *namedHashPtr;
878      int new;      int new;
879      NamedFont *nfPtr;          NamedFont *nfPtr;    
880    
881      fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;      fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
882    
883      namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new);      namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new);
884                                            
885      if (new == 0) {      if (new == 0) {
886          nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);          nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
887          if (nfPtr->deletePending == 0) {          if (nfPtr->deletePending == 0) {
888              Tcl_ResetResult(interp);              Tcl_ResetResult(interp);
889              Tcl_AppendResult(interp, "named font \"", name,              Tcl_AppendResult(interp, "named font \"", name,
890                      "\" already exists", (char *) NULL);                      "\" already exists", (char *) NULL);
891              return TCL_ERROR;              return TCL_ERROR;
892          }          }
893    
894          /*          /*
895           * Recreating a named font with the same name as a previous           * Recreating a named font with the same name as a previous
896           * named font.  Some widgets were still using that named           * named font.  Some widgets were still using that named
897           * font, so they need to get redisplayed.           * font, so they need to get redisplayed.
898           */           */
899    
900          nfPtr->fa = *faPtr;          nfPtr->fa = *faPtr;
901          nfPtr->deletePending = 0;          nfPtr->deletePending = 0;
902          UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);          UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);
903          return TCL_OK;          return TCL_OK;
904      }      }
905    
906      nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont));      nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont));
907      nfPtr->deletePending = 0;      nfPtr->deletePending = 0;
908      Tcl_SetHashValue(namedHashPtr, nfPtr);      Tcl_SetHashValue(namedHashPtr, nfPtr);
909      nfPtr->fa = *faPtr;      nfPtr->fa = *faPtr;
910      nfPtr->refCount = 0;              nfPtr->refCount = 0;        
911      nfPtr->deletePending = 0;      nfPtr->deletePending = 0;
912      return TCL_OK;      return TCL_OK;
913  }  }
914    
915  /*  /*
916   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
917   *   *
918   * Tk_GetFont --   * Tk_GetFont --
919   *   *
920   *      Given a string description of a font, map the description to a   *      Given a string description of a font, map the description to a
921   *      corresponding Tk_Font that represents the font.   *      corresponding Tk_Font that represents the font.
922   *   *
923   * Results:   * Results:
924   *      The return value is token for the font, or NULL if an error   *      The return value is token for the font, or NULL if an error
925   *      prevented the font from being created.  If NULL is returned, an   *      prevented the font from being created.  If NULL is returned, an
926   *      error message will be left in the interp's result.   *      error message will be left in the interp's result.
927   *   *
928   * Side effects:   * Side effects:
929   *      The font is added to an internal database with a reference   *      The font is added to an internal database with a reference
930   *      count.  For each call to this procedure, there should eventually   *      count.  For each call to this procedure, there should eventually
931   *      be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the   *      be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the
932   *      database is cleaned up when fonts aren't in use anymore.   *      database is cleaned up when fonts aren't in use anymore.
933   *   *
934   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
935   */   */
936    
937  Tk_Font  Tk_Font
938  Tk_GetFont(interp, tkwin, string)  Tk_GetFont(interp, tkwin, string)
939      Tcl_Interp *interp;         /* Interp for database and error return. */      Tcl_Interp *interp;         /* Interp for database and error return. */
940      Tk_Window tkwin;            /* For display on which font will be used. */      Tk_Window tkwin;            /* For display on which font will be used. */
941      CONST char *string;         /* String describing font, as: named font,      CONST char *string;         /* String describing font, as: named font,
942                                   * native format, or parseable string. */                                   * native format, or parseable string. */
943  {  {
944      Tk_Font tkfont;      Tk_Font tkfont;
945      Tcl_Obj *strPtr;      Tcl_Obj *strPtr;
946    
947      strPtr = Tcl_NewStringObj((char *) string, -1);      strPtr = Tcl_NewStringObj((char *) string, -1);
948      Tcl_IncrRefCount(strPtr);      Tcl_IncrRefCount(strPtr);
949      tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr);      tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr);
950      Tcl_DecrRefCount(strPtr);        Tcl_DecrRefCount(strPtr);  
951      return tkfont;      return tkfont;
952  }  }
953    
954  /*  /*
955   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
956   *   *
957   * Tk_AllocFontFromObj --   * Tk_AllocFontFromObj --
958   *   *
959   *      Given a string description of a font, map the description to a   *      Given a string description of a font, map the description to a
960   *      corresponding Tk_Font that represents the font.   *      corresponding Tk_Font that represents the font.
961   *   *
962   * Results:   * Results:
963   *      The return value is token for the font, or NULL if an error   *      The return value is token for the font, or NULL if an error
964   *      prevented the font from being created.  If NULL is returned, an   *      prevented the font from being created.  If NULL is returned, an
965   *      error message will be left in interp's result object.   *      error message will be left in interp's result object.
966   *   *
967   * Side effects:   * Side effects:
968   *      The font is added to an internal database with a reference   *      The font is added to an internal database with a reference
969   *      count.  For each call to this procedure, there should eventually   *      count.  For each call to this procedure, there should eventually
970   *      be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the   *      be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the
971   *      database is cleaned up when fonts aren't in use anymore.   *      database is cleaned up when fonts aren't in use anymore.
972   *   *
973   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
974   */   */
975    
976  Tk_Font  Tk_Font
977  Tk_AllocFontFromObj(interp, tkwin, objPtr)  Tk_AllocFontFromObj(interp, tkwin, objPtr)
978      Tcl_Interp *interp;         /* Interp for database and error return. */      Tcl_Interp *interp;         /* Interp for database and error return. */
979      Tk_Window tkwin;            /* For screen on which font will be used. */      Tk_Window tkwin;            /* For screen on which font will be used. */
980      Tcl_Obj *objPtr;            /* Object describing font, as: named font,      Tcl_Obj *objPtr;            /* Object describing font, as: named font,
981                                   * native format, or parseable string. */                                   * native format, or parseable string. */
982  {  {
983      TkFontInfo *fiPtr;      TkFontInfo *fiPtr;
984      Tcl_HashEntry *cacheHashPtr, *namedHashPtr;      Tcl_HashEntry *cacheHashPtr, *namedHashPtr;
985      TkFont *fontPtr, *firstFontPtr, *oldFontPtr;      TkFont *fontPtr, *firstFontPtr, *oldFontPtr;
986      int new, descent;      int new, descent;
987      NamedFont *nfPtr;      NamedFont *nfPtr;
988    
989      fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;      fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
990      if (objPtr->typePtr != &fontObjType) {      if (objPtr->typePtr != &fontObjType) {
991          SetFontFromAny(interp, objPtr);          SetFontFromAny(interp, objPtr);
992      }      }
993    
994      oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;      oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
995    
996      if (oldFontPtr != NULL) {      if (oldFontPtr != NULL) {
997          if (oldFontPtr->resourceRefCount == 0) {          if (oldFontPtr->resourceRefCount == 0) {
998              /*              /*
999               * This is a stale reference: it refers to a TkFont that's               * This is a stale reference: it refers to a TkFont that's
1000               * no longer in use.  Clear the reference.               * no longer in use.  Clear the reference.
1001               */               */
1002    
1003              FreeFontObjProc(objPtr);              FreeFontObjProc(objPtr);
1004              oldFontPtr = NULL;              oldFontPtr = NULL;
1005          } else if (Tk_Screen(tkwin) == oldFontPtr->screen) {          } else if (Tk_Screen(tkwin) == oldFontPtr->screen) {
1006              oldFontPtr->resourceRefCount++;              oldFontPtr->resourceRefCount++;
1007              return (Tk_Font) oldFontPtr;              return (Tk_Font) oldFontPtr;
1008          }          }
1009      }      }
1010    
1011      /*      /*
1012       * Next, search the list of fonts that have the name we want, to see       * Next, search the list of fonts that have the name we want, to see
1013       * if one of them is for the right screen.       * if one of them is for the right screen.
1014       */       */
1015    
1016      new = 0;      new = 0;
1017      if (oldFontPtr != NULL) {      if (oldFontPtr != NULL) {
1018          cacheHashPtr = oldFontPtr->cacheHashPtr;          cacheHashPtr = oldFontPtr->cacheHashPtr;
1019          FreeFontObjProc(objPtr);          FreeFontObjProc(objPtr);
1020      } else {      } else {
1021          cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache,          cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache,
1022                  Tcl_GetString(objPtr), &new);                  Tcl_GetString(objPtr), &new);
1023      }      }
1024      firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);      firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
1025      for (fontPtr = firstFontPtr; (fontPtr != NULL);      for (fontPtr = firstFontPtr; (fontPtr != NULL);
1026              fontPtr = fontPtr->nextPtr) {              fontPtr = fontPtr->nextPtr) {
1027          if (Tk_Screen(tkwin) == fontPtr->screen) {          if (Tk_Screen(tkwin) == fontPtr->screen) {
1028              fontPtr->resourceRefCount++;              fontPtr->resourceRefCount++;
1029              fontPtr->objRefCount++;              fontPtr->objRefCount++;
1030              objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;              objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
1031              return (Tk_Font) fontPtr;              return (Tk_Font) fontPtr;
1032          }          }
1033      }      }
1034    
1035      /*      /*
1036       * The desired font isn't in the table.  Make a new one.       * The desired font isn't in the table.  Make a new one.
1037       */       */
1038    
1039      namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable,      namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable,
1040              Tcl_GetString(objPtr));              Tcl_GetString(objPtr));
1041      if (namedHashPtr != NULL) {      if (namedHashPtr != NULL) {
1042          /*          /*
1043           * Construct a font based on a named font.           * Construct a font based on a named font.
1044           */           */
1045    
1046          nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);          nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
1047          nfPtr->refCount++;          nfPtr->refCount++;
1048    
1049          fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa);          fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa);
1050      } else {      } else {
1051          /*          /*
1052           * Native font?           * Native font?
1053           */           */
1054    
1055          fontPtr = TkpGetNativeFont(tkwin, Tcl_GetString(objPtr));          fontPtr = TkpGetNativeFont(tkwin, Tcl_GetString(objPtr));
1056          if (fontPtr == NULL) {          if (fontPtr == NULL) {
1057              TkFontAttributes fa;              TkFontAttributes fa;
1058              Tcl_Obj *dupObjPtr = Tcl_DuplicateObj(objPtr);              Tcl_Obj *dupObjPtr = Tcl_DuplicateObj(objPtr);
1059    
1060              if (ParseFontNameObj(interp, tkwin, dupObjPtr, &fa) != TCL_OK) {              if (ParseFontNameObj(interp, tkwin, dupObjPtr, &fa) != TCL_OK) {
1061                  if (new) {                  if (new) {
1062                      Tcl_DeleteHashEntry(cacheHashPtr);                      Tcl_DeleteHashEntry(cacheHashPtr);
1063                  }                  }
1064                  Tcl_DecrRefCount(dupObjPtr);                  Tcl_DecrRefCount(dupObjPtr);
1065                  return NULL;                  return NULL;
1066              }              }
1067              Tcl_DecrRefCount(dupObjPtr);              Tcl_DecrRefCount(dupObjPtr);
1068    
1069              /*              /*
1070               * String contained the attributes inline.               * String contained the attributes inline.
1071               */               */
1072    
1073              fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa);              fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa);
1074          }          }
1075      }      }
1076    
1077      fontPtr->resourceRefCount = 1;      fontPtr->resourceRefCount = 1;
1078      fontPtr->objRefCount = 1;      fontPtr->objRefCount = 1;
1079      fontPtr->cacheHashPtr = cacheHashPtr;      fontPtr->cacheHashPtr = cacheHashPtr;
1080      fontPtr->namedHashPtr = namedHashPtr;      fontPtr->namedHashPtr = namedHashPtr;
1081      fontPtr->screen = Tk_Screen(tkwin);      fontPtr->screen = Tk_Screen(tkwin);
1082      fontPtr->nextPtr = firstFontPtr;      fontPtr->nextPtr = firstFontPtr;
1083      Tcl_SetHashValue(cacheHashPtr, fontPtr);      Tcl_SetHashValue(cacheHashPtr, fontPtr);
1084    
1085      Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, -1, 0, &fontPtr->tabWidth);      Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, -1, 0, &fontPtr->tabWidth);
1086      if (fontPtr->tabWidth == 0) {      if (fontPtr->tabWidth == 0) {
1087          fontPtr->tabWidth = fontPtr->fm.maxWidth;          fontPtr->tabWidth = fontPtr->fm.maxWidth;
1088      }      }
1089      fontPtr->tabWidth *= 8;      fontPtr->tabWidth *= 8;
1090    
1091      /*      /*
1092       * Make sure the tab width isn't zero (some fonts may not have enough       * Make sure the tab width isn't zero (some fonts may not have enough
1093       * information to set a reasonable tab width).       * information to set a reasonable tab width).
1094       */       */
1095    
1096      if (fontPtr->tabWidth == 0) {      if (fontPtr->tabWidth == 0) {
1097          fontPtr->tabWidth = 1;          fontPtr->tabWidth = 1;
1098      }      }
1099    
1100      /*      /*
1101       * Get information used for drawing underlines in generic code on a       * Get information used for drawing underlines in generic code on a
1102       * non-underlined font.       * non-underlined font.
1103       */       */
1104            
1105      descent = fontPtr->fm.descent;      descent = fontPtr->fm.descent;
1106      fontPtr->underlinePos = descent / 2;      fontPtr->underlinePos = descent / 2;
1107      fontPtr->underlineHeight = TkFontGetPixels(tkwin, fontPtr->fa.size) / 10;      fontPtr->underlineHeight = TkFontGetPixels(tkwin, fontPtr->fa.size) / 10;
1108      if (fontPtr->underlineHeight == 0) {      if (fontPtr->underlineHeight == 0) {
1109          fontPtr->underlineHeight = 1;          fontPtr->underlineHeight = 1;
1110      }      }
1111      if (fontPtr->underlinePos + fontPtr->underlineHeight > descent) {      if (fontPtr->underlinePos + fontPtr->underlineHeight > descent) {
1112          /*          /*
1113           * If this set of values would cause the bottom of the underline           * If this set of values would cause the bottom of the underline
1114           * bar to stick below the descent of the font, jack the underline           * bar to stick below the descent of the font, jack the underline
1115           * up a bit higher.           * up a bit higher.
1116           */           */
1117    
1118          fontPtr->underlineHeight = descent - fontPtr->underlinePos;          fontPtr->underlineHeight = descent - fontPtr->underlinePos;
1119          if (fontPtr->underlineHeight == 0) {          if (fontPtr->underlineHeight == 0) {
1120              fontPtr->underlinePos--;              fontPtr->underlinePos--;
1121              fontPtr->underlineHeight = 1;              fontPtr->underlineHeight = 1;
1122          }          }
1123      }      }
1124            
1125      objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;      objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
1126      return (Tk_Font) fontPtr;      return (Tk_Font) fontPtr;
1127  }  }
1128    
1129  /*  /*
1130   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1131   *   *
1132   * Tk_GetFontFromObj --   * Tk_GetFontFromObj --
1133   *   *
1134   *      Find the font that corresponds to a given object.  The font must   *      Find the font that corresponds to a given object.  The font must
1135   *      have already been created by Tk_GetFont or Tk_AllocFontFromObj.   *      have already been created by Tk_GetFont or Tk_AllocFontFromObj.
1136   *   *
1137   * Results:   * Results:
1138   *      The return value is a token for the font that matches objPtr   *      The return value is a token for the font that matches objPtr
1139   *      and is suitable for use in tkwin.   *      and is suitable for use in tkwin.
1140   *   *
1141   * Side effects:   * Side effects:
1142   *      If the object is not already a font ref, the conversion will free   *      If the object is not already a font ref, the conversion will free
1143   *      any old internal representation.   *      any old internal representation.
1144   *   *
1145   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1146   */   */
1147    
1148  Tk_Font  Tk_Font
1149  Tk_GetFontFromObj(tkwin, objPtr)  Tk_GetFontFromObj(tkwin, objPtr)
1150      Tk_Window tkwin;            /* The window that the font will be used in. */      Tk_Window tkwin;            /* The window that the font will be used in. */
1151      Tcl_Obj *objPtr;            /* The object from which to get the font. */      Tcl_Obj *objPtr;            /* The object from which to get the font. */
1152  {  {
1153      TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;      TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
1154      TkFont *fontPtr;      TkFont *fontPtr;
1155      Tcl_HashEntry *hashPtr;      Tcl_HashEntry *hashPtr;
1156    
1157      if (objPtr->typePtr != &fontObjType) {      if (objPtr->typePtr != &fontObjType) {
1158          SetFontFromAny((Tcl_Interp *) NULL, objPtr);          SetFontFromAny((Tcl_Interp *) NULL, objPtr);
1159      }      }
1160    
1161      fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;      fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
1162    
1163      if (fontPtr != NULL) {      if (fontPtr != NULL) {
1164          if (fontPtr->resourceRefCount == 0) {          if (fontPtr->resourceRefCount == 0) {
1165              /*              /*
1166               * This is a stale reference: it refers to a TkFont that's               * This is a stale reference: it refers to a TkFont that's
1167               * no longer in use.  Clear the reference.               * no longer in use.  Clear the reference.
1168               */               */
1169    
1170              FreeFontObjProc(objPtr);              FreeFontObjProc(objPtr);
1171              fontPtr = NULL;              fontPtr = NULL;
1172          } else if (Tk_Screen(tkwin) == fontPtr->screen) {          } else if (Tk_Screen(tkwin) == fontPtr->screen) {
1173              return (Tk_Font) fontPtr;              return (Tk_Font) fontPtr;
1174          }          }
1175      }      }
1176    
1177      /*      /*
1178       * Next, search the list of fonts that have the name we want, to see       * Next, search the list of fonts that have the name we want, to see
1179       * if one of them is for the right screen.       * if one of them is for the right screen.
1180       */       */
1181    
1182      if (fontPtr != NULL) {      if (fontPtr != NULL) {
1183          hashPtr = fontPtr->cacheHashPtr;          hashPtr = fontPtr->cacheHashPtr;
1184          FreeFontObjProc(objPtr);          FreeFontObjProc(objPtr);
1185      } else {      } else {
1186          hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr));          hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr));
1187      }      }
1188      if (hashPtr != NULL) {      if (hashPtr != NULL) {
1189          for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL;          for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL;
1190                  fontPtr = fontPtr->nextPtr) {                  fontPtr = fontPtr->nextPtr) {
1191              if (Tk_Screen(tkwin) == fontPtr->screen) {              if (Tk_Screen(tkwin) == fontPtr->screen) {
1192                  fontPtr->objRefCount++;                  fontPtr->objRefCount++;
1193                  objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;                  objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
1194                  return (Tk_Font) fontPtr;                  return (Tk_Font) fontPtr;
1195              }              }
1196          }          }
1197      }      }
1198    
1199      panic("Tk_GetFontFromObj called with non-existent font!");      panic("Tk_GetFontFromObj called with non-existent font!");
1200      return NULL;      return NULL;
1201  }  }
1202    
1203  /*  /*
1204   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1205   *   *
1206   * SetFontFromAny --   * SetFontFromAny --
1207   *   *
1208   *      Convert the internal representation of a Tcl object to the   *      Convert the internal representation of a Tcl object to the
1209   *      font internal form.   *      font internal form.
1210   *   *
1211   * Results:   * Results:
1212   *      Always returns TCL_OK.   *      Always returns TCL_OK.
1213   *   *
1214   * Side effects:   * Side effects:
1215   *      The object is left with its typePtr pointing to fontObjType.   *      The object is left with its typePtr pointing to fontObjType.
1216   *      The TkFont pointer is NULL.   *      The TkFont pointer is NULL.
1217   *   *
1218   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1219   */   */
1220    
1221  static int  static int
1222  SetFontFromAny(interp, objPtr)  SetFontFromAny(interp, objPtr)
1223      Tcl_Interp *interp;         /* Used for error reporting if not NULL. */      Tcl_Interp *interp;         /* Used for error reporting if not NULL. */
1224      Tcl_Obj *objPtr;            /* The object to convert. */      Tcl_Obj *objPtr;            /* The object to convert. */
1225  {  {
1226      Tcl_ObjType *typePtr;      Tcl_ObjType *typePtr;
1227    
1228      /*      /*
1229       * Free the old internalRep before setting the new one.       * Free the old internalRep before setting the new one.
1230       */       */
1231    
1232      Tcl_GetString(objPtr);      Tcl_GetString(objPtr);
1233      typePtr = objPtr->typePtr;      typePtr = objPtr->typePtr;
1234      if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {      if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
1235          (*typePtr->freeIntRepProc)(objPtr);          (*typePtr->freeIntRepProc)(objPtr);
1236      }      }
1237      objPtr->typePtr = &fontObjType;      objPtr->typePtr = &fontObjType;
1238      objPtr->internalRep.twoPtrValue.ptr1 = NULL;      objPtr->internalRep.twoPtrValue.ptr1 = NULL;
1239    
1240      return TCL_OK;      return TCL_OK;
1241  }  }
1242    
1243  /*  /*
1244   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1245   *   *
1246   * Tk_NameOfFont --   * Tk_NameOfFont --
1247   *   *
1248   *      Given a font, return a textual string identifying it.   *      Given a font, return a textual string identifying it.
1249   *   *
1250   * Results:   * Results:
1251   *      The return value is the description that was passed to   *      The return value is the description that was passed to
1252   *      Tk_GetFont() to create the font.  The storage for the returned   *      Tk_GetFont() to create the font.  The storage for the returned
1253   *      string is only guaranteed to persist until the font is deleted.   *      string is only guaranteed to persist until the font is deleted.
1254   *      The caller should not modify this string.   *      The caller should not modify this string.
1255   *   *
1256   * Side effects:   * Side effects:
1257   *      None.   *      None.
1258   *   *
1259   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1260   */   */
1261    
1262  char *  char *
1263  Tk_NameOfFont(tkfont)  Tk_NameOfFont(tkfont)
1264      Tk_Font tkfont;             /* Font whose name is desired. */      Tk_Font tkfont;             /* Font whose name is desired. */
1265  {  {
1266      TkFont *fontPtr;      TkFont *fontPtr;
1267    
1268      fontPtr = (TkFont *) tkfont;      fontPtr = (TkFont *) tkfont;
1269      return fontPtr->cacheHashPtr->key.string;      return fontPtr->cacheHashPtr->key.string;
1270  }  }
1271    
1272  /*  /*
1273   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1274   *   *
1275   * Tk_FreeFont --   * Tk_FreeFont --
1276   *   *
1277   *      Called to release a font allocated by Tk_GetFont().   *      Called to release a font allocated by Tk_GetFont().
1278   *   *
1279   * Results:   * Results:
1280   *      None.   *      None.
1281   *   *
1282   * Side effects:   * Side effects:
1283   *      The reference count associated with font is decremented, and   *      The reference count associated with font is decremented, and
1284   *      only deallocated when no one is using it.   *      only deallocated when no one is using it.
1285   *   *
1286   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1287   */   */
1288    
1289  void  void
1290  Tk_FreeFont(tkfont)  Tk_FreeFont(tkfont)
1291      Tk_Font tkfont;             /* Font to be released. */      Tk_Font tkfont;             /* Font to be released. */
1292  {  {
1293      TkFont *fontPtr, *prevPtr;      TkFont *fontPtr, *prevPtr;
1294      NamedFont *nfPtr;      NamedFont *nfPtr;
1295    
1296      if (tkfont == NULL) {      if (tkfont == NULL) {
1297          return;          return;
1298      }      }
1299      fontPtr = (TkFont *) tkfont;      fontPtr = (TkFont *) tkfont;
1300      fontPtr->resourceRefCount--;      fontPtr->resourceRefCount--;
1301      if (fontPtr->resourceRefCount > 0) {      if (fontPtr->resourceRefCount > 0) {
1302          return;          return;
1303      }      }
1304      if (fontPtr->namedHashPtr != NULL) {      if (fontPtr->namedHashPtr != NULL) {
1305          /*          /*
1306           * This font derived from a named font.  Reduce the reference           * This font derived from a named font.  Reduce the reference
1307           * count on the named font and free it if no-one else is           * count on the named font and free it if no-one else is
1308           * using it.           * using it.
1309           */           */
1310    
1311          nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr);          nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr);
1312          nfPtr->refCount--;          nfPtr->refCount--;
1313          if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) {          if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) {
1314              Tcl_DeleteHashEntry(fontPtr->namedHashPtr);              Tcl_DeleteHashEntry(fontPtr->namedHashPtr);
1315              ckfree((char *) nfPtr);              ckfree((char *) nfPtr);
1316          }          }
1317      }      }
1318    
1319      prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr);      prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr);
1320      if (prevPtr == fontPtr) {      if (prevPtr == fontPtr) {
1321          if (fontPtr->nextPtr == NULL) {          if (fontPtr->nextPtr == NULL) {
1322              Tcl_DeleteHashEntry(fontPtr->cacheHashPtr);              Tcl_DeleteHashEntry(fontPtr->cacheHashPtr);
1323          } else  {          } else  {
1324              Tcl_SetHashValue(fontPtr->cacheHashPtr, fontPtr->nextPtr);              Tcl_SetHashValue(fontPtr->cacheHashPtr, fontPtr->nextPtr);
1325          }          }
1326      } else {      } else {
1327          while (prevPtr->nextPtr != fontPtr) {          while (prevPtr->nextPtr != fontPtr) {
1328              prevPtr = prevPtr->nextPtr;              prevPtr = prevPtr->nextPtr;
1329          }          }
1330          prevPtr->nextPtr = fontPtr->nextPtr;          prevPtr->nextPtr = fontPtr->nextPtr;
1331      }      }
1332    
1333      TkpDeleteFont(fontPtr);      TkpDeleteFont(fontPtr);
1334      if (fontPtr->objRefCount == 0) {      if (fontPtr->objRefCount == 0) {
1335          ckfree((char *) fontPtr);          ckfree((char *) fontPtr);
1336      }      }
1337  }  }
1338    
1339  /*  /*
1340   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1341   *   *
1342   * Tk_FreeFontFromObj --   * Tk_FreeFontFromObj --
1343   *   *
1344   *      Called to release a font inside a Tcl_Obj *. Decrements the refCount   *      Called to release a font inside a Tcl_Obj *. Decrements the refCount
1345   *      of the font and removes it from the hash tables if necessary.   *      of the font and removes it from the hash tables if necessary.
1346   *   *
1347   * Results:   * Results:
1348   *      None.   *      None.
1349   *   *
1350   * Side effects:   * Side effects:
1351   *      The reference count associated with font is decremented, and   *      The reference count associated with font is decremented, and
1352   *      only deallocated when no one is using it.   *      only deallocated when no one is using it.
1353   *   *
1354   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1355   */   */
1356    
1357  void  void
1358  Tk_FreeFontFromObj(tkwin, objPtr)  Tk_FreeFontFromObj(tkwin, objPtr)
1359      Tk_Window tkwin;            /* The window this font lives in. Needed      Tk_Window tkwin;            /* The window this font lives in. Needed
1360                                   * for the screen value. */                                   * for the screen value. */
1361      Tcl_Obj *objPtr;            /* The Tcl_Obj * to be freed. */      Tcl_Obj *objPtr;            /* The Tcl_Obj * to be freed. */
1362  {  {
1363      Tk_FreeFont(Tk_GetFontFromObj(tkwin, objPtr));      Tk_FreeFont(Tk_GetFontFromObj(tkwin, objPtr));
1364  }  }
1365    
1366  /*  /*
1367   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1368   *   *
1369   * FreeFontObjProc --   * FreeFontObjProc --
1370   *   *
1371   *      This proc is called to release an object reference to a font.   *      This proc is called to release an object reference to a font.
1372   *      Called when the object's internal rep is released or when   *      Called when the object's internal rep is released or when
1373   *      the cached fontPtr needs to be changed.   *      the cached fontPtr needs to be changed.
1374   *   *
1375   * Results:   * Results:
1376   *      None.   *      None.
1377   *   *
1378   * Side effects:   * Side effects:
1379   *      The object reference count is decremented. When both it   *      The object reference count is decremented. When both it
1380   *      and the hash ref count go to zero, the font's resources   *      and the hash ref count go to zero, the font's resources
1381   *      are released.   *      are released.
1382   *   *
1383   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1384   */   */
1385    
1386  static void  static void
1387  FreeFontObjProc(objPtr)  FreeFontObjProc(objPtr)
1388      Tcl_Obj *objPtr;            /* The object we are releasing. */      Tcl_Obj *objPtr;            /* The object we are releasing. */
1389  {  {
1390      TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;      TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
1391    
1392      if (fontPtr != NULL) {      if (fontPtr != NULL) {
1393          fontPtr->objRefCount--;          fontPtr->objRefCount--;
1394          if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) {          if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) {
1395              ckfree((char *) fontPtr);              ckfree((char *) fontPtr);
1396              objPtr->internalRep.twoPtrValue.ptr1 = NULL;              objPtr->internalRep.twoPtrValue.ptr1 = NULL;
1397          }          }
1398      }      }
1399  }  }
1400    
1401  /*  /*
1402   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1403   *   *
1404   * DupFontObjProc --   * DupFontObjProc --
1405   *   *
1406   *      When a cached font object is duplicated, this is called to   *      When a cached font object is duplicated, this is called to
1407   *      update the internal reps.   *      update the internal reps.
1408   *   *
1409   * Results:   * Results:
1410   *      None.   *      None.
1411   *   *
1412   * Side effects:   * Side effects:
1413   *      The font's objRefCount is incremented and the internal rep   *      The font's objRefCount is incremented and the internal rep
1414   *      of the copy is set to point to it.   *      of the copy is set to point to it.
1415   *   *
1416   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1417   */   */
1418    
1419  static void  static void
1420  DupFontObjProc(srcObjPtr, dupObjPtr)  DupFontObjProc(srcObjPtr, dupObjPtr)
1421      Tcl_Obj *srcObjPtr;         /* The object we are copying from. */      Tcl_Obj *srcObjPtr;         /* The object we are copying from. */
1422      Tcl_Obj *dupObjPtr;         /* The object we are copying to. */      Tcl_Obj *dupObjPtr;         /* The object we are copying to. */
1423  {  {
1424      TkFont *fontPtr = (TkFont *) srcObjPtr->internalRep.twoPtrValue.ptr1;      TkFont *fontPtr = (TkFont *) srcObjPtr->internalRep.twoPtrValue.ptr1;
1425            
1426      dupObjPtr->typePtr = srcObjPtr->typePtr;      dupObjPtr->typePtr = srcObjPtr->typePtr;
1427      dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;      dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
1428    
1429      if (fontPtr != NULL) {      if (fontPtr != NULL) {
1430          fontPtr->objRefCount++;          fontPtr->objRefCount++;
1431      }      }
1432  }  }
1433    
1434  /*  /*
1435   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1436   *   *
1437   * Tk_FontId --   * Tk_FontId --
1438   *   *
1439   *      Given a font, return an opaque handle that should be selected   *      Given a font, return an opaque handle that should be selected
1440   *      into the XGCValues structure in order to get the constructed   *      into the XGCValues structure in order to get the constructed
1441   *      gc to use this font.  This procedure would go away if the   *      gc to use this font.  This procedure would go away if the
1442   *      XGCValues structure were replaced with a TkGCValues structure.   *      XGCValues structure were replaced with a TkGCValues structure.
1443   *   *
1444   * Results:   * Results:
1445   *      As above.   *      As above.
1446   *   *
1447   * Side effects:   * Side effects:
1448   *      None.   *      None.
1449   *   *
1450   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1451   */   */
1452    
1453  Font  Font
1454  Tk_FontId(tkfont)  Tk_FontId(tkfont)
1455      Tk_Font tkfont;     /* Font that is going to be selected into GC. */      Tk_Font tkfont;     /* Font that is going to be selected into GC. */
1456  {  {
1457      TkFont *fontPtr;      TkFont *fontPtr;
1458    
1459      fontPtr = (TkFont *) tkfont;      fontPtr = (TkFont *) tkfont;
1460      return fontPtr->fid;      return fontPtr->fid;
1461  }  }
1462    
1463  /*  /*
1464   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1465   *   *
1466   * Tk_GetFontMetrics --   * Tk_GetFontMetrics --
1467   *   *
1468   *      Returns overall ascent and descent metrics for the given font.   *      Returns overall ascent and descent metrics for the given font.
1469   *      These values can be used to space multiple lines of text and   *      These values can be used to space multiple lines of text and
1470   *      to align the baselines of text in different fonts.   *      to align the baselines of text in different fonts.
1471   *   *
1472   * Results:   * Results:
1473   *      If *heightPtr is non-NULL, it is filled with the overall height   *      If *heightPtr is non-NULL, it is filled with the overall height
1474   *      of the font, which is the sum of the ascent and descent.   *      of the font, which is the sum of the ascent and descent.
1475   *      If *ascentPtr or *descentPtr is non-NULL, they are filled with   *      If *ascentPtr or *descentPtr is non-NULL, they are filled with
1476   *      the ascent and/or descent information for the font.   *      the ascent and/or descent information for the font.
1477   *   *
1478   * Side effects:   * Side effects:
1479   *      None.   *      None.
1480   *   *
1481   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1482   */   */
1483  void  void
1484  Tk_GetFontMetrics(tkfont, fmPtr)  Tk_GetFontMetrics(tkfont, fmPtr)
1485      Tk_Font tkfont;             /* Font in which metrics are calculated. */      Tk_Font tkfont;             /* Font in which metrics are calculated. */
1486      Tk_FontMetrics *fmPtr;      /* Pointer to structure in which font      Tk_FontMetrics *fmPtr;      /* Pointer to structure in which font
1487                                   * metrics for tkfont will be stored. */                                   * metrics for tkfont will be stored. */
1488  {  {
1489      TkFont *fontPtr;      TkFont *fontPtr;
1490    
1491      fontPtr = (TkFont *) tkfont;      fontPtr = (TkFont *) tkfont;
1492      fmPtr->ascent = fontPtr->fm.ascent;      fmPtr->ascent = fontPtr->fm.ascent;
1493      fmPtr->descent = fontPtr->fm.descent;      fmPtr->descent = fontPtr->fm.descent;
1494      fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent;      fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent;
1495  }  }
1496    
1497  /*  /*
1498   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1499   *   *
1500   * Tk_PostscriptFontName --   * Tk_PostscriptFontName --
1501   *   *
1502   *      Given a Tk_Font, return the name of the corresponding Postscript   *      Given a Tk_Font, return the name of the corresponding Postscript
1503   *      font.   *      font.
1504   *   *
1505   * Results:   * Results:
1506   *      The return value is the pointsize of the given Tk_Font.   *      The return value is the pointsize of the given Tk_Font.
1507   *      The name of the Postscript font is appended to dsPtr.   *      The name of the Postscript font is appended to dsPtr.
1508   *   *
1509   * Side effects:   * Side effects:
1510   *      If the font does not exist on the printer, the print job will   *      If the font does not exist on the printer, the print job will
1511   *      fail at print time.  Given a "reasonable" Postscript printer,   *      fail at print time.  Given a "reasonable" Postscript printer,
1512   *      the following Tk_Font font families should print correctly:   *      the following Tk_Font font families should print correctly:
1513   *   *
1514   *          Avant Garde, Arial, Bookman, Courier, Courier New, Geneva,   *          Avant Garde, Arial, Bookman, Courier, Courier New, Geneva,
1515   *          Helvetica, Monaco, New Century Schoolbook, New York,   *          Helvetica, Monaco, New Century Schoolbook, New York,
1516   *          Palatino, Symbol, Times, Times New Roman, Zapf Chancery,   *          Palatino, Symbol, Times, Times New Roman, Zapf Chancery,
1517   *          and Zapf Dingbats.   *          and Zapf Dingbats.
1518   *   *
1519   *      Any other Tk_Font font families may not print correctly   *      Any other Tk_Font font families may not print correctly
1520   *      because the computed Postscript font name may be incorrect.   *      because the computed Postscript font name may be incorrect.
1521   *   *
1522   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1523   */   */
1524    
1525  int  int
1526  Tk_PostscriptFontName(tkfont, dsPtr)  Tk_PostscriptFontName(tkfont, dsPtr)
1527      Tk_Font tkfont;             /* Font in which text will be printed. */      Tk_Font tkfont;             /* Font in which text will be printed. */
1528      Tcl_DString *dsPtr;         /* Pointer to an initialized Tcl_DString to      Tcl_DString *dsPtr;         /* Pointer to an initialized Tcl_DString to
1529                                   * which the name of the Postscript font that                                   * which the name of the Postscript font that
1530                                   * corresponds to tkfont will be appended. */                                   * corresponds to tkfont will be appended. */
1531  {  {
1532      TkFont *fontPtr;      TkFont *fontPtr;
1533      char *family, *weightString, *slantString;      char *family, *weightString, *slantString;
1534      char *src, *dest;      char *src, *dest;
1535      int upper, len;      int upper, len;
1536    
1537      len = Tcl_DStringLength(dsPtr);      len = Tcl_DStringLength(dsPtr);
1538      fontPtr = (TkFont *) tkfont;      fontPtr = (TkFont *) tkfont;
1539    
1540      /*      /*
1541       * Convert the case-insensitive Tk_Font family name to the       * Convert the case-insensitive Tk_Font family name to the
1542       * case-sensitive Postscript family name.  Take out any spaces and       * case-sensitive Postscript family name.  Take out any spaces and
1543       * capitalize the first letter of each word.       * capitalize the first letter of each word.
1544       */       */
1545    
1546      family = fontPtr->fa.family;      family = fontPtr->fa.family;
1547      if (strncasecmp(family, "itc ", 4) == 0) {      if (strncasecmp(family, "itc ", 4) == 0) {
1548          family = family + 4;          family = family + 4;
1549      }      }
1550      if ((strcasecmp(family, "Arial") == 0)      if ((strcasecmp(family, "Arial") == 0)
1551              || (strcasecmp(family, "Geneva") == 0)) {              || (strcasecmp(family, "Geneva") == 0)) {
1552          family = "Helvetica";          family = "Helvetica";
1553      } else if ((strcasecmp(family, "Times New Roman") == 0)      } else if ((strcasecmp(family, "Times New Roman") == 0)
1554              || (strcasecmp(family, "New York") == 0)) {              || (strcasecmp(family, "New York") == 0)) {
1555          family = "Times";          family = "Times";
1556      } else if ((strcasecmp(family, "Courier New") == 0)      } else if ((strcasecmp(family, "Courier New") == 0)
1557              || (strcasecmp(family, "Monaco") == 0)) {              || (strcasecmp(family, "Monaco") == 0)) {
1558          family = "Courier";          family = "Courier";
1559      } else if (strcasecmp(family, "AvantGarde") == 0) {      } else if (strcasecmp(family, "AvantGarde") == 0) {
1560          family = "AvantGarde";          family = "AvantGarde";
1561      } else if (strcasecmp(family, "ZapfChancery") == 0) {      } else if (strcasecmp(family, "ZapfChancery") == 0) {
1562          family = "ZapfChancery";          family = "ZapfChancery";
1563      } else if (strcasecmp(family, "ZapfDingbats") == 0) {      } else if (strcasecmp(family, "ZapfDingbats") == 0) {
1564          family = "ZapfDingbats";          family = "ZapfDingbats";
1565      } else {      } else {
1566          Tcl_UniChar ch;          Tcl_UniChar ch;
1567    
1568          /*          /*
1569           * Inline, capitalize the first letter of each word, lowercase the           * Inline, capitalize the first letter of each word, lowercase the
1570           * rest of the letters in each word, and then take out the spaces           * rest of the letters in each word, and then take out the spaces
1571           * between the words.  This may make the DString shorter, which is           * between the words.  This may make the DString shorter, which is
1572           * safe to do.           * safe to do.
1573           */           */
1574    
1575          Tcl_DStringAppend(dsPtr, family, -1);          Tcl_DStringAppend(dsPtr, family, -1);
1576    
1577          src = dest = Tcl_DStringValue(dsPtr) + len;          src = dest = Tcl_DStringValue(dsPtr) + len;
1578          upper = 1;          upper = 1;
1579          for (; *src != '\0'; ) {          for (; *src != '\0'; ) {
1580              while (isspace(UCHAR(*src))) { /* INTL: ISO space */              while (isspace(UCHAR(*src))) { /* INTL: ISO space */
1581                  src++;                  src++;
1582                  upper = 1;                  upper = 1;
1583              }              }
1584              src += Tcl_UtfToUniChar(src, &ch);              src += Tcl_UtfToUniChar(src, &ch);
1585              if (upper) {              if (upper) {
1586                  ch = Tcl_UniCharToUpper(ch);                  ch = Tcl_UniCharToUpper(ch);
1587                  upper = 0;                  upper = 0;
1588              } else {              } else {
1589                  ch = Tcl_UniCharToLower(ch);                  ch = Tcl_UniCharToLower(ch);
1590              }              }
1591              dest += Tcl_UniCharToUtf(ch, dest);              dest += Tcl_UniCharToUtf(ch, dest);
1592          }          }
1593          *dest = '\0';          *dest = '\0';
1594          Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr));          Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr));
1595          family = Tcl_DStringValue(dsPtr) + len;          family = Tcl_DStringValue(dsPtr) + len;
1596      }      }
1597      if (family != Tcl_DStringValue(dsPtr) + len) {      if (family != Tcl_DStringValue(dsPtr) + len) {
1598          Tcl_DStringAppend(dsPtr, family, -1);          Tcl_DStringAppend(dsPtr, family, -1);
1599          family = Tcl_DStringValue(dsPtr) + len;          family = Tcl_DStringValue(dsPtr) + len;
1600      }      }
1601    
1602      if (strcasecmp(family, "NewCenturySchoolbook") == 0) {      if (strcasecmp(family, "NewCenturySchoolbook") == 0) {
1603          Tcl_DStringSetLength(dsPtr, len);          Tcl_DStringSetLength(dsPtr, len);
1604          Tcl_DStringAppend(dsPtr, "NewCenturySchlbk", -1);          Tcl_DStringAppend(dsPtr, "NewCenturySchlbk", -1);
1605          family = Tcl_DStringValue(dsPtr) + len;          family = Tcl_DStringValue(dsPtr) + len;
1606      }      }
1607    
1608      /*      /*
1609       * Get the string to use for the weight.       * Get the string to use for the weight.
1610       */       */
1611    
1612      weightString = NULL;      weightString = NULL;
1613      if (fontPtr->fa.weight == TK_FW_NORMAL) {      if (fontPtr->fa.weight == TK_FW_NORMAL) {
1614          if (strcmp(family, "Bookman") == 0) {          if (strcmp(family, "Bookman") == 0) {
1615              weightString = "Light";              weightString = "Light";
1616          } else if (strcmp(family, "AvantGarde") == 0) {          } else if (strcmp(family, "AvantGarde") == 0) {
1617              weightString = "Book";              weightString = "Book";
1618          } else if (strcmp(family, "ZapfChancery") == 0) {          } else if (strcmp(family, "ZapfChancery") == 0) {
1619              weightString = "Medium";              weightString = "Medium";
1620          }          }
1621      } else {      } else {
1622          if ((strcmp(family, "Bookman") == 0)          if ((strcmp(family, "Bookman") == 0)
1623                  || (strcmp(family, "AvantGarde") == 0)) {                  || (strcmp(family, "AvantGarde") == 0)) {
1624              weightString = "Demi";              weightString = "Demi";
1625          } else {          } else {
1626              weightString = "Bold";              weightString = "Bold";
1627          }          }
1628      }      }
1629    
1630      /*      /*
1631       * Get the string to use for the slant.       * Get the string to use for the slant.
1632       */       */
1633    
1634      slantString = NULL;      slantString = NULL;
1635      if (fontPtr->fa.slant == TK_FS_ROMAN) {      if (fontPtr->fa.slant == TK_FS_ROMAN) {
1636          ;          ;
1637      } else {      } else {
1638          if ((strcmp(family, "Helvetica") == 0)          if ((strcmp(family, "Helvetica") == 0)
1639                  || (strcmp(family, "Courier") == 0)                  || (strcmp(family, "Courier") == 0)
1640                  || (strcmp(family, "AvantGarde") == 0)) {                  || (strcmp(family, "AvantGarde") == 0)) {
1641              slantString = "Oblique";              slantString = "Oblique";
1642          } else {          } else {
1643              slantString = "Italic";              slantString = "Italic";
1644          }          }
1645      }      }
1646    
1647      /*      /*
1648       * The string "Roman" needs to be added to some fonts that are not bold       * The string "Roman" needs to be added to some fonts that are not bold
1649       * and not italic.       * and not italic.
1650       */       */
1651    
1652      if ((slantString == NULL) && (weightString == NULL)) {      if ((slantString == NULL) && (weightString == NULL)) {
1653          if ((strcmp(family, "Times") == 0)          if ((strcmp(family, "Times") == 0)
1654                  || (strcmp(family, "NewCenturySchlbk") == 0)                  || (strcmp(family, "NewCenturySchlbk") == 0)
1655                  || (strcmp(family, "Palatino") == 0)) {                  || (strcmp(family, "Palatino") == 0)) {
1656              Tcl_DStringAppend(dsPtr, "-Roman", -1);              Tcl_DStringAppend(dsPtr, "-Roman", -1);
1657          }          }
1658      } else {      } else {
1659          Tcl_DStringAppend(dsPtr, "-", -1);          Tcl_DStringAppend(dsPtr, "-", -1);
1660          if (weightString != NULL) {          if (weightString != NULL) {
1661              Tcl_DStringAppend(dsPtr, weightString, -1);              Tcl_DStringAppend(dsPtr, weightString, -1);
1662          }          }
1663          if (slantString != NULL) {          if (slantString != NULL) {
1664              Tcl_DStringAppend(dsPtr, slantString, -1);              Tcl_DStringAppend(dsPtr, slantString, -1);
1665          }          }
1666      }      }
1667    
1668      return fontPtr->fa.size;      return fontPtr->fa.size;
1669  }  }
1670    
1671  /*  /*
1672   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1673   *   *
1674   * Tk_TextWidth --   * Tk_TextWidth --
1675   *   *
1676   *      A wrapper function for the more complicated interface of   *      A wrapper function for the more complicated interface of
1677   *      Tk_MeasureChars.  Computes how much space the given   *      Tk_MeasureChars.  Computes how much space the given
1678   *      simple string needs.   *      simple string needs.
1679   *   *
1680   * Results:   * Results:
1681   *      The return value is the width (in pixels) of the given string.   *      The return value is the width (in pixels) of the given string.
1682   *   *
1683   * Side effects:   * Side effects:
1684   *      None.   *      None.
1685   *   *
1686   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1687   */   */
1688    
1689  int  int
1690  Tk_TextWidth(tkfont, string, numBytes)  Tk_TextWidth(tkfont, string, numBytes)
1691      Tk_Font tkfont;             /* Font in which text will be measured. */      Tk_Font tkfont;             /* Font in which text will be measured. */
1692      CONST char *string;         /* String whose width will be computed. */      CONST char *string;         /* String whose width will be computed. */
1693      int numBytes;               /* Number of bytes to consider from      int numBytes;               /* Number of bytes to consider from
1694                                   * string, or < 0 for strlen(). */                                   * string, or < 0 for strlen(). */
1695  {  {
1696      int width;      int width;
1697    
1698      if (numBytes < 0) {      if (numBytes < 0) {
1699          numBytes = strlen(string);          numBytes = strlen(string);
1700      }      }
1701      Tk_MeasureChars(tkfont, string, numBytes, -1, 0, &width);      Tk_MeasureChars(tkfont, string, numBytes, -1, 0, &width);
1702      return width;      return width;
1703  }  }
1704    
1705  /*  /*
1706   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1707   *   *
1708   * Tk_UnderlineChars --   * Tk_UnderlineChars --
1709   *   *
1710   *      This procedure draws an underline for a given range of characters   *      This procedure draws an underline for a given range of characters
1711   *      in a given string.  It doesn't draw the characters (which are   *      in a given string.  It doesn't draw the characters (which are
1712   *      assumed to have been displayed previously); it just draws the   *      assumed to have been displayed previously); it just draws the
1713   *      underline.  This procedure would mainly be used to quickly   *      underline.  This procedure would mainly be used to quickly
1714   *      underline a few characters without having to construct an   *      underline a few characters without having to construct an
1715   *      underlined font.  To produce properly underlined text, the   *      underlined font.  To produce properly underlined text, the
1716   *      appropriate underlined font should be constructed and used.   *      appropriate underlined font should be constructed and used.
1717   *   *
1718   * Results:   * Results:
1719   *      None.   *      None.
1720   *   *
1721   * Side effects:   * Side effects:
1722   *      Information gets displayed in "drawable".   *      Information gets displayed in "drawable".
1723   *   *
1724   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1725   */   */
1726    
1727  void  void
1728  Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstByte,  Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstByte,
1729          lastByte)          lastByte)
1730      Display *display;           /* Display on which to draw. */      Display *display;           /* Display on which to draw. */
1731      Drawable drawable;          /* Window or pixmap in which to draw. */      Drawable drawable;          /* Window or pixmap in which to draw. */
1732      GC gc;                      /* Graphics context for actually drawing      GC gc;                      /* Graphics context for actually drawing
1733                                   * line. */                                   * line. */
1734      Tk_Font tkfont;             /* Font used in GC;  must have been allocated      Tk_Font tkfont;             /* Font used in GC;  must have been allocated
1735                                   * by Tk_GetFont().  Used for character                                   * by Tk_GetFont().  Used for character
1736                                   * dimensions, etc. */                                   * dimensions, etc. */
1737      CONST char *string;         /* String containing characters to be      CONST char *string;         /* String containing characters to be
1738                                   * underlined or overstruck. */                                   * underlined or overstruck. */
1739      int x, y;                   /* Coordinates at which first character of      int x, y;                   /* Coordinates at which first character of
1740                                   * string is drawn. */                                   * string is drawn. */
1741      int firstByte;              /* Index of first byte of first character. */      int firstByte;              /* Index of first byte of first character. */
1742      int lastByte;               /* Index of first byte after the last      int lastByte;               /* Index of first byte after the last
1743                                   * character. */                                   * character. */
1744  {  {
1745      TkFont *fontPtr;      TkFont *fontPtr;
1746      int startX, endX;      int startX, endX;
1747    
1748      fontPtr = (TkFont *) tkfont;      fontPtr = (TkFont *) tkfont;
1749            
1750      Tk_MeasureChars(tkfont, string, firstByte, -1, 0, &startX);      Tk_MeasureChars(tkfont, string, firstByte, -1, 0, &startX);
1751      Tk_MeasureChars(tkfont, string, lastByte, -1, 0, &endX);      Tk_MeasureChars(tkfont, string, lastByte, -1, 0, &endX);
1752    
1753      XFillRectangle(display, drawable, gc, x + startX,      XFillRectangle(display, drawable, gc, x + startX,
1754              y + fontPtr->underlinePos, (unsigned int) (endX - startX),              y + fontPtr->underlinePos, (unsigned int) (endX - startX),
1755              (unsigned int) fontPtr->underlineHeight);              (unsigned int) fontPtr->underlineHeight);
1756  }  }
1757    
1758  /*  /*
1759   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1760   *   *
1761   * Tk_ComputeTextLayout --   * Tk_ComputeTextLayout --
1762   *   *
1763   *      Computes the amount of screen space needed to display a   *      Computes the amount of screen space needed to display a
1764   *      multi-line, justified string of text.  Records all the   *      multi-line, justified string of text.  Records all the
1765   *      measurements that were done to determine to size and   *      measurements that were done to determine to size and
1766   *      positioning of the individual lines of text; this information   *      positioning of the individual lines of text; this information
1767   *      can be used by the Tk_DrawTextLayout() procedure to   *      can be used by the Tk_DrawTextLayout() procedure to
1768   *      display the text quickly (without remeasuring it).   *      display the text quickly (without remeasuring it).
1769   *   *
1770   *      This procedure is useful for simple widgets that want to   *      This procedure is useful for simple widgets that want to
1771   *      display single-font, multi-line text and want Tk to handle the   *      display single-font, multi-line text and want Tk to handle the
1772   *      details.   *      details.
1773   *   *
1774   * Results:   * Results:
1775   *      The return value is a Tk_TextLayout token that holds the   *      The return value is a Tk_TextLayout token that holds the
1776   *      measurement information for the given string.  The token is   *      measurement information for the given string.  The token is
1777   *      only valid for the given string.  If the string is freed,   *      only valid for the given string.  If the string is freed,
1778   *      the token is no longer valid and must also be freed.  To free   *      the token is no longer valid and must also be freed.  To free
1779   *      the token, call Tk_FreeTextLayout().   *      the token, call Tk_FreeTextLayout().
1780   *   *
1781   *      The dimensions of the screen area needed to display the text   *      The dimensions of the screen area needed to display the text
1782   *      are stored in *widthPtr and *heightPtr.   *      are stored in *widthPtr and *heightPtr.
1783   *   *
1784   * Side effects:   * Side effects:
1785   *      Memory is allocated to hold the measurement information.     *      Memory is allocated to hold the measurement information.  
1786   *   *
1787   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
1788   */   */
1789    
1790  Tk_TextLayout  Tk_TextLayout
1791  Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags,  Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags,
1792          widthPtr, heightPtr)          widthPtr, heightPtr)
1793      Tk_Font tkfont;             /* Font that will be used to display text. */      Tk_Font tkfont;             /* Font that will be used to display text. */
1794      CONST char *string;         /* String whose dimensions are to be      CONST char *string;         /* String whose dimensions are to be
1795                                   * computed. */                                   * computed. */
1796      int numChars;               /* Number of characters to consider from      int numChars;               /* Number of characters to consider from
1797                                   * string, or < 0 for strlen(). */                                   * string, or < 0 for strlen(). */
1798      int wrapLength;             /* Longest permissible line length, in      int wrapLength;             /* Longest permissible line length, in
1799                                   * pixels.  <= 0 means no automatic wrapping:                                   * pixels.  <= 0 means no automatic wrapping:
1800                                   * just let lines get as long as needed. */                                   * just let lines get as long as needed. */
1801      Tk_Justify justify;         /* How to justify lines. */      Tk_Justify justify;         /* How to justify lines. */
1802      int flags;                  /* Flag bits OR-ed together.      int flags;                  /* Flag bits OR-ed together.
1803                                   * TK_IGNORE_TABS means that tab characters                                   * TK_IGNORE_TABS means that tab characters
1804                                   * should not be expanded.  TK_IGNORE_NEWLINES                                   * should not be expanded.  TK_IGNORE_NEWLINES
1805                                   * means that newline characters should not                                   * means that newline characters should not
1806                                   * cause a line break. */                                   * cause a line break. */
1807      int *widthPtr;              /* Filled with width of string. */      int *widthPtr;              /* Filled with width of string. */
1808      int *heightPtr;             /* Filled with height of string. */      int *heightPtr;             /* Filled with height of string. */
1809  {  {
1810      TkFont *fontPtr;      TkFont *fontPtr;
1811      CONST char *start, *end, *special;      CONST char *start, *end, *special;
1812      int n, y, bytesThisChunk, maxChunks;      int n, y, bytesThisChunk, maxChunks;
1813      int baseline, height, curX, newX, maxWidth;      int baseline, height, curX, newX, maxWidth;
1814      TextLayout *layoutPtr;      TextLayout *layoutPtr;
1815      LayoutChunk *chunkPtr;      LayoutChunk *chunkPtr;
1816      CONST TkFontMetrics *fmPtr;      CONST TkFontMetrics *fmPtr;
1817      Tcl_DString lineBuffer;      Tcl_DString lineBuffer;
1818      int *lineLengths;      int *lineLengths;
1819      int curLine, layoutHeight;      int curLine, layoutHeight;
1820    
1821      Tcl_DStringInit(&lineBuffer);      Tcl_DStringInit(&lineBuffer);
1822            
1823      fontPtr = (TkFont *) tkfont;      fontPtr = (TkFont *) tkfont;
1824      if ((fontPtr == NULL) || (string == NULL)) {      if ((fontPtr == NULL) || (string == NULL)) {
1825          if (widthPtr != NULL) {          if (widthPtr != NULL) {
1826              *widthPtr = 0;              *widthPtr = 0;
1827          }          }
1828          if (heightPtr != NULL) {          if (heightPtr != NULL) {
1829              *heightPtr = 0;              *heightPtr = 0;
1830          }          }
1831          return NULL;          return NULL;
1832      }      }
1833    
1834      fmPtr = &fontPtr->fm;      fmPtr = &fontPtr->fm;
1835    
1836      height = fmPtr->ascent + fmPtr->descent;      height = fmPtr->ascent + fmPtr->descent;
1837    
1838      if (numChars < 0) {      if (numChars < 0) {
1839          numChars = Tcl_NumUtfChars(string, -1);          numChars = Tcl_NumUtfChars(string, -1);
1840      }      }
1841      if (wrapLength == 0) {      if (wrapLength == 0) {
1842          wrapLength = -1;          wrapLength = -1;
1843      }      }
1844    
1845      maxChunks = 1;      maxChunks = 1;
1846    
1847      layoutPtr = (TextLayout *) ckalloc(sizeof(TextLayout)      layoutPtr = (TextLayout *) ckalloc(sizeof(TextLayout)
1848              + (maxChunks - 1) * sizeof(LayoutChunk));              + (maxChunks - 1) * sizeof(LayoutChunk));
1849      layoutPtr->tkfont       = tkfont;      layoutPtr->tkfont       = tkfont;
1850      layoutPtr->string       = string;      layoutPtr->string       = string;
1851      layoutPtr->numChunks    = 0;      layoutPtr->numChunks    = 0;
1852    
1853      baseline = fmPtr->ascent;      baseline = fmPtr->ascent;
1854      maxWidth = 0;      maxWidth = 0;
1855    
1856      /*      /*
1857       * Divide the string up into simple strings and measure each string.       * Divide the string up into simple strings and measure each string.
1858       */       */
1859    
1860      curX = 0;      curX = 0;
1861    
1862      end = Tcl_UtfAtIndex(string, numChars);      end = Tcl_UtfAtIndex(string, numChars);
1863      special = string;      special = string;
1864    
1865      flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES;      flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES;
1866      flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE;            flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE;      
1867      for (start = string; start < end; ) {      for (start = string; start < end; ) {
1868          if (start >= special) {          if (start >= special) {
1869              /*              /*
1870               * Find the next special character in the string.               * Find the next special character in the string.
1871               *               *
1872               * INTL: Note that it is safe to increment by byte, because we are               * INTL: Note that it is safe to increment by byte, because we are
1873               * looking for 7-bit characters that will appear unchanged in               * looking for 7-bit characters that will appear unchanged in
1874               * UTF-8.  At some point we may need to support the full Unicode               * UTF-8.  At some point we may need to support the full Unicode
1875               * whitespace set.               * whitespace set.
1876               */               */
1877    
1878              for (special = start; special < end; special++) {              for (special = start; special < end; special++) {
1879                  if (!(flags & TK_IGNORE_NEWLINES)) {                  if (!(flags & TK_IGNORE_NEWLINES)) {
1880                      if ((*special == '\n') || (*special == '\r')) {                      if ((*special == '\n') || (*special == '\r')) {
1881                          break;                          break;
1882                      }                      }
1883                  }                  }
1884                  if (!(flags & TK_IGNORE_TABS)) {                  if (!(flags & TK_IGNORE_TABS)) {
1885                      if (*special == '\t') {                      if (*special == '\t') {
1886                          break;                          break;
1887                      }                      }
1888                  }                  }
1889              }              }
1890          }          }
1891    
1892          /*          /*
1893           * Special points at the next special character (or the end of the           * Special points at the next special character (or the end of the
1894           * string).  Process characters between start and special.           * string).  Process characters between start and special.
1895           */           */
1896    
1897          chunkPtr = NULL;          chunkPtr = NULL;
1898          if (start < special) {          if (start < special) {
1899              bytesThisChunk = Tk_MeasureChars(tkfont, start, special - start,              bytesThisChunk = Tk_MeasureChars(tkfont, start, special - start,
1900                      wrapLength - curX, flags, &newX);                      wrapLength - curX, flags, &newX);
1901              newX += curX;              newX += curX;
1902              flags &= ~TK_AT_LEAST_ONE;              flags &= ~TK_AT_LEAST_ONE;
1903              if (bytesThisChunk > 0) {              if (bytesThisChunk > 0) {
1904                  chunkPtr = NewChunk(&layoutPtr, &maxChunks, start,                  chunkPtr = NewChunk(&layoutPtr, &maxChunks, start,
1905                          bytesThisChunk, curX, newX, baseline);                          bytesThisChunk, curX, newX, baseline);
1906                                                    
1907                  start += bytesThisChunk;                  start += bytesThisChunk;
1908                  curX = newX;                  curX = newX;
1909              }              }
1910          }          }
1911    
1912          if ((start == special) && (special < end)) {          if ((start == special) && (special < end)) {
1913              /*              /*
1914               * Handle the special character.               * Handle the special character.
1915               *               *
1916               * INTL: Special will be pointing at a 7-bit character so we               * INTL: Special will be pointing at a 7-bit character so we
1917               * can safely treat it as a single byte.               * can safely treat it as a single byte.
1918               */               */
1919    
1920              chunkPtr = NULL;              chunkPtr = NULL;
1921              if (*special == '\t') {              if (*special == '\t') {
1922                  newX = curX + fontPtr->tabWidth;                  newX = curX + fontPtr->tabWidth;
1923                  newX -= newX % fontPtr->tabWidth;                  newX -= newX % fontPtr->tabWidth;
1924                  NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX,                  NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX,
1925                          baseline)->numDisplayChars = -1;                          baseline)->numDisplayChars = -1;
1926                  start++;                  start++;
1927                  if ((start < end) &&                  if ((start < end) &&
1928                          ((wrapLength <= 0) || (newX <= wrapLength))) {                          ((wrapLength <= 0) || (newX <= wrapLength))) {
1929                      /*                      /*
1930                       * More chars can still fit on this line.                       * More chars can still fit on this line.
1931                       */                       */
1932    
1933                      curX = newX;                      curX = newX;
1934                      flags &= ~TK_AT_LEAST_ONE;                      flags &= ~TK_AT_LEAST_ONE;
1935                      continue;                      continue;
1936                  }                  }
1937              } else {                  } else {    
1938                  NewChunk(&layoutPtr, &maxChunks, start, 1, curX, curX,                  NewChunk(&layoutPtr, &maxChunks, start, 1, curX, curX,
1939                          baseline)->numDisplayChars = -1;                          baseline)->numDisplayChars = -1;
1940                  start++;                  start++;
1941                  goto wrapLine;                  goto wrapLine;
1942              }              }
1943          }          }
1944    
1945          /*          /*
1946           * No more characters are going to go on this line, either because           * No more characters are going to go on this line, either because
1947           * no more characters can fit or there are no more characters left.           * no more characters can fit or there are no more characters left.
1948           * Consume all extra spaces at end of line.             * Consume all extra spaces at end of line.  
1949           */           */
1950    
1951          while ((start < end) && isspace(UCHAR(*start))) { /* INTL: ISO space */          while ((start < end) && isspace(UCHAR(*start))) { /* INTL: ISO space */
1952              if (!(flags & TK_IGNORE_NEWLINES)) {              if (!(flags & TK_IGNORE_NEWLINES)) {
1953                  if ((*start == '\n') || (*start == '\r')) {                  if ((*start == '\n') || (*start == '\r')) {
1954                      break;                      break;
1955                  }                  }
1956              }              }
1957              if (!(flags & TK_IGNORE_TABS)) {              if (!(flags & TK_IGNORE_TABS)) {
1958                  if (*start == '\t') {                  if (*start == '\t') {
1959                      break;                      break;
1960                  }                  }
1961              }              }
1962              start++;              start++;
1963          }          }
1964          if (chunkPtr != NULL) {          if (chunkPtr != NULL) {
1965              CONST char *end;              CONST char *end;
1966    
1967              /*              /*
1968               * Append all the extra spaces on this line to the end of the               * Append all the extra spaces on this line to the end of the
1969               * last text chunk.  This is a little tricky because we are               * last text chunk.  This is a little tricky because we are
1970               * switching back and forth between characters and bytes.               * switching back and forth between characters and bytes.
1971               */               */
1972    
1973              end = chunkPtr->start + chunkPtr->numBytes;              end = chunkPtr->start + chunkPtr->numBytes;
1974              bytesThisChunk = start - end;              bytesThisChunk = start - end;
1975              if (bytesThisChunk > 0) {              if (bytesThisChunk > 0) {
1976                  bytesThisChunk = Tk_MeasureChars(tkfont, end, bytesThisChunk,                  bytesThisChunk = Tk_MeasureChars(tkfont, end, bytesThisChunk,
1977                          -1, 0, &chunkPtr->totalWidth);                          -1, 0, &chunkPtr->totalWidth);
1978                  chunkPtr->numBytes += bytesThisChunk;                  chunkPtr->numBytes += bytesThisChunk;
1979                  chunkPtr->numChars += Tcl_NumUtfChars(end, bytesThisChunk);                  chunkPtr->numChars += Tcl_NumUtfChars(end, bytesThisChunk);
1980                  chunkPtr->totalWidth += curX;                  chunkPtr->totalWidth += curX;
1981              }              }
1982          }          }
1983    
1984          wrapLine:          wrapLine:
1985          flags |= TK_AT_LEAST_ONE;          flags |= TK_AT_LEAST_ONE;
1986    
1987          /*          /*
1988           * Save current line length, then move current position to start of           * Save current line length, then move current position to start of
1989           * next line.           * next line.
1990           */           */
1991    
1992          if (curX > maxWidth) {          if (curX > maxWidth) {
1993              maxWidth = curX;              maxWidth = curX;
1994          }          }
1995    
1996          /*          /*
1997           * Remember width of this line, so that all chunks on this line           * Remember width of this line, so that all chunks on this line
1998           * can be centered or right justified, if necessary.           * can be centered or right justified, if necessary.
1999           */           */
2000    
2001          Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));          Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
2002    
2003          curX = 0;          curX = 0;
2004          baseline += height;          baseline += height;
2005      }      }
2006    
2007      /*      /*
2008       * If last line ends with a newline, then we need to make a 0 width       * If last line ends with a newline, then we need to make a 0 width
2009       * chunk on the next line.  Otherwise "Hello" and "Hello\n" are the       * chunk on the next line.  Otherwise "Hello" and "Hello\n" are the
2010       * same height.       * same height.
2011       */       */
2012    
2013      if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) {      if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) {
2014          if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') {          if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') {
2015              chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX,              chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX,
2016                      curX, baseline);                      curX, baseline);
2017              chunkPtr->numDisplayChars = -1;              chunkPtr->numDisplayChars = -1;
2018              Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));              Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
2019              baseline += height;              baseline += height;
2020          }          }
2021      }            }      
2022    
2023      layoutPtr->width = maxWidth;      layoutPtr->width = maxWidth;
2024      layoutHeight = baseline - fmPtr->ascent;      layoutHeight = baseline - fmPtr->ascent;
2025      if (layoutPtr->numChunks == 0) {      if (layoutPtr->numChunks == 0) {
2026          layoutHeight = height;          layoutHeight = height;
2027    
2028          /*          /*
2029           * This fake chunk is used by the other procedures so that they can           * This fake chunk is used by the other procedures so that they can
2030           * pretend that there is a chunk with no chars in it, which makes           * pretend that there is a chunk with no chars in it, which makes
2031           * the coding simpler.           * the coding simpler.
2032           */           */
2033    
2034          layoutPtr->numChunks = 1;          layoutPtr->numChunks = 1;
2035          layoutPtr->chunks[0].start              = string;          layoutPtr->chunks[0].start              = string;
2036          layoutPtr->chunks[0].numBytes           = 0;          layoutPtr->chunks[0].numBytes           = 0;
2037          layoutPtr->chunks[0].numChars           = 0;          layoutPtr->chunks[0].numChars           = 0;
2038          layoutPtr->chunks[0].numDisplayChars    = -1;          layoutPtr->chunks[0].numDisplayChars    = -1;
2039          layoutPtr->chunks[0].x                  = 0;          layoutPtr->chunks[0].x                  = 0;
2040          layoutPtr->chunks[0].y                  = fmPtr->ascent;          layoutPtr->chunks[0].y                  = fmPtr->ascent;
2041          layoutPtr->chunks[0].totalWidth         = 0;          layoutPtr->chunks[0].totalWidth         = 0;
2042          layoutPtr->chunks[0].displayWidth       = 0;          layoutPtr->chunks[0].displayWidth       = 0;
2043      } else {      } else {
2044          /*          /*
2045           * Using maximum line length, shift all the chunks so that the lines           * Using maximum line length, shift all the chunks so that the lines
2046           * are all justified correctly.           * are all justified correctly.
2047           */           */
2048            
2049          curLine = 0;          curLine = 0;
2050          chunkPtr = layoutPtr->chunks;          chunkPtr = layoutPtr->chunks;
2051          y = chunkPtr->y;          y = chunkPtr->y;
2052          lineLengths = (int *) Tcl_DStringValue(&lineBuffer);          lineLengths = (int *) Tcl_DStringValue(&lineBuffer);
2053          for (n = 0; n < layoutPtr->numChunks; n++) {          for (n = 0; n < layoutPtr->numChunks; n++) {
2054              int extra;              int extra;
2055    
2056              if (chunkPtr->y != y) {              if (chunkPtr->y != y) {
2057                  curLine++;                  curLine++;
2058                  y = chunkPtr->y;                  y = chunkPtr->y;
2059              }              }
2060              extra = maxWidth - lineLengths[curLine];              extra = maxWidth - lineLengths[curLine];
2061              if (justify == TK_JUSTIFY_CENTER) {              if (justify == TK_JUSTIFY_CENTER) {
2062                  chunkPtr->x += extra / 2;                  chunkPtr->x += extra / 2;
2063              } else if (justify == TK_JUSTIFY_RIGHT) {              } else if (justify == TK_JUSTIFY_RIGHT) {
2064                  chunkPtr->x += extra;                  chunkPtr->x += extra;
2065              }              }
2066              chunkPtr++;              chunkPtr++;
2067          }          }
2068      }      }
2069    
2070      if (widthPtr != NULL) {      if (widthPtr != NULL) {
2071          *widthPtr = layoutPtr->width;          *widthPtr = layoutPtr->width;
2072      }      }
2073      if (heightPtr != NULL) {      if (heightPtr != NULL) {
2074          *heightPtr = layoutHeight;          *heightPtr = layoutHeight;
2075      }      }
2076      Tcl_DStringFree(&lineBuffer);      Tcl_DStringFree(&lineBuffer);
2077    
2078      return (Tk_TextLayout) layoutPtr;      return (Tk_TextLayout) layoutPtr;
2079  }  }
2080    
2081  /*  /*
2082   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2083   *   *
2084   * Tk_FreeTextLayout --   * Tk_FreeTextLayout --
2085   *   *
2086   *      This procedure is called to release the storage associated with   *      This procedure is called to release the storage associated with
2087   *      a Tk_TextLayout when it is no longer needed.   *      a Tk_TextLayout when it is no longer needed.
2088   *   *
2089   * Results:   * Results:
2090   *      None.   *      None.
2091   *   *
2092   * Side effects:   * Side effects:
2093   *      Memory is freed.   *      Memory is freed.
2094   *   *
2095   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2096   */   */
2097    
2098  void  void
2099  Tk_FreeTextLayout(textLayout)  Tk_FreeTextLayout(textLayout)
2100      Tk_TextLayout textLayout;   /* The text layout to be released. */      Tk_TextLayout textLayout;   /* The text layout to be released. */
2101  {  {
2102      TextLayout *layoutPtr;      TextLayout *layoutPtr;
2103    
2104      layoutPtr = (TextLayout *) textLayout;      layoutPtr = (TextLayout *) textLayout;
2105      if (layoutPtr != NULL) {      if (layoutPtr != NULL) {
2106          ckfree((char *) layoutPtr);          ckfree((char *) layoutPtr);
2107      }      }
2108  }  }
2109    
2110  /*  /*
2111   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2112   *   *
2113   * Tk_DrawTextLayout --   * Tk_DrawTextLayout --
2114   *   *
2115   *      Use the information in the Tk_TextLayout token to display a   *      Use the information in the Tk_TextLayout token to display a
2116   *      multi-line, justified string of text.   *      multi-line, justified string of text.
2117   *   *
2118   *      This procedure is useful for simple widgets that need to   *      This procedure is useful for simple widgets that need to
2119   *      display single-font, multi-line text and want Tk to handle   *      display single-font, multi-line text and want Tk to handle
2120   *      the details.   *      the details.
2121   *   *
2122   * Results:   * Results:
2123   *      None.   *      None.
2124   *   *
2125   * Side effects:   * Side effects:
2126   *      Text drawn on the screen.   *      Text drawn on the screen.
2127   *   *
2128   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2129   */   */
2130    
2131  void  void
2132  Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar)  Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar)
2133      Display *display;           /* Display on which to draw. */      Display *display;           /* Display on which to draw. */
2134      Drawable drawable;          /* Window or pixmap in which to draw. */      Drawable drawable;          /* Window or pixmap in which to draw. */
2135      GC gc;                      /* Graphics context to use for drawing text. */      GC gc;                      /* Graphics context to use for drawing text. */
2136      Tk_TextLayout layout;       /* Layout information, from a previous call      Tk_TextLayout layout;       /* Layout information, from a previous call
2137                                   * to Tk_ComputeTextLayout(). */                                   * to Tk_ComputeTextLayout(). */
2138      int x, y;                   /* Upper-left hand corner of rectangle in      int x, y;                   /* Upper-left hand corner of rectangle in
2139                                   * which to draw (pixels). */                                   * which to draw (pixels). */
2140      int firstChar;              /* The index of the first character to draw      int firstChar;              /* The index of the first character to draw
2141                                   * from the given text item.  0 specfies the                                   * from the given text item.  0 specfies the
2142                                   * beginning. */                                   * beginning. */
2143      int lastChar;               /* The index just after the last character      int lastChar;               /* The index just after the last character
2144                                   * to draw from the given text item.  A number                                   * to draw from the given text item.  A number
2145                                   * < 0 means to draw all characters. */                                   * < 0 means to draw all characters. */
2146  {  {
2147      TextLayout *layoutPtr;      TextLayout *layoutPtr;
2148      int i, numDisplayChars, drawX;      int i, numDisplayChars, drawX;
2149      CONST char *firstByte;      CONST char *firstByte;
2150      CONST char *lastByte;      CONST char *lastByte;
2151      LayoutChunk *chunkPtr;      LayoutChunk *chunkPtr;
2152    
2153      layoutPtr = (TextLayout *) layout;      layoutPtr = (TextLayout *) layout;
2154      if (layoutPtr == NULL) {      if (layoutPtr == NULL) {
2155          return;          return;
2156      }      }
2157    
2158      if (lastChar < 0) {      if (lastChar < 0) {
2159          lastChar = 100000000;          lastChar = 100000000;
2160      }      }
2161      chunkPtr = layoutPtr->chunks;      chunkPtr = layoutPtr->chunks;
2162      for (i = 0; i < layoutPtr->numChunks; i++) {      for (i = 0; i < layoutPtr->numChunks; i++) {
2163          numDisplayChars = chunkPtr->numDisplayChars;          numDisplayChars = chunkPtr->numDisplayChars;
2164          if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {          if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {
2165              if (firstChar <= 0) {              if (firstChar <= 0) {
2166                  drawX = 0;                  drawX = 0;
2167                  firstChar = 0;                  firstChar = 0;
2168                  firstByte = chunkPtr->start;                  firstByte = chunkPtr->start;
2169              } else {              } else {
2170                  firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar);                  firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar);
2171                  Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start,                  Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start,
2172                          firstByte - chunkPtr->start, -1, 0, &drawX);                          firstByte - chunkPtr->start, -1, 0, &drawX);
2173              }              }
2174              if (lastChar < numDisplayChars) {              if (lastChar < numDisplayChars) {
2175                  numDisplayChars = lastChar;                  numDisplayChars = lastChar;
2176              }              }
2177              lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars);              lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars);
2178              Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,              Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,
2179                      firstByte, lastByte - firstByte,                      firstByte, lastByte - firstByte,
2180                      x + chunkPtr->x + drawX, y + chunkPtr->y);                      x + chunkPtr->x + drawX, y + chunkPtr->y);
2181          }          }
2182          firstChar -= chunkPtr->numChars;          firstChar -= chunkPtr->numChars;
2183          lastChar -= chunkPtr->numChars;          lastChar -= chunkPtr->numChars;
2184          if (lastChar <= 0) {          if (lastChar <= 0) {
2185              break;              break;
2186          }          }
2187          chunkPtr++;          chunkPtr++;
2188      }      }
2189  }  }
2190    
2191  /*  /*
2192   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2193   *   *
2194   * Tk_UnderlineTextLayout --   * Tk_UnderlineTextLayout --
2195   *   *
2196   *      Use the information in the Tk_TextLayout token to display an   *      Use the information in the Tk_TextLayout token to display an
2197   *      underline below an individual character.  This procedure does   *      underline below an individual character.  This procedure does
2198   *      not draw the text, just the underline.   *      not draw the text, just the underline.
2199   *   *
2200   *      This procedure is useful for simple widgets that need to   *      This procedure is useful for simple widgets that need to
2201   *      display single-font, multi-line text with an individual   *      display single-font, multi-line text with an individual
2202   *      character underlined and want Tk to handle the details.   *      character underlined and want Tk to handle the details.
2203   *      To display larger amounts of underlined text, construct   *      To display larger amounts of underlined text, construct
2204   *      and use an underlined font.   *      and use an underlined font.
2205   *   *
2206   * Results:   * Results:
2207   *      None.   *      None.
2208   *   *
2209   * Side effects:   * Side effects:
2210   *      Underline drawn on the screen.   *      Underline drawn on the screen.
2211   *   *
2212   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2213   */   */
2214    
2215  void  void
2216  Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline)  Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline)
2217      Display *display;           /* Display on which to draw. */      Display *display;           /* Display on which to draw. */
2218      Drawable drawable;          /* Window or pixmap in which to draw. */      Drawable drawable;          /* Window or pixmap in which to draw. */
2219      GC gc;                      /* Graphics context to use for drawing text. */      GC gc;                      /* Graphics context to use for drawing text. */
2220      Tk_TextLayout layout;       /* Layout information, from a previous call      Tk_TextLayout layout;       /* Layout information, from a previous call
2221                                   * to Tk_ComputeTextLayout(). */                                   * to Tk_ComputeTextLayout(). */
2222      int x, y;                   /* Upper-left hand corner of rectangle in      int x, y;                   /* Upper-left hand corner of rectangle in
2223                                   * which to draw (pixels). */                                   * which to draw (pixels). */
2224      int underline;              /* Index of the single character to      int underline;              /* Index of the single character to
2225                                   * underline, or -1 for no underline. */                                   * underline, or -1 for no underline. */
2226  {  {
2227      TextLayout *layoutPtr;      TextLayout *layoutPtr;
2228      TkFont *fontPtr;      TkFont *fontPtr;
2229      int xx, yy, width, height;      int xx, yy, width, height;
2230    
2231      if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0)      if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0)
2232              && (width != 0)) {              && (width != 0)) {
2233          layoutPtr = (TextLayout *) layout;          layoutPtr = (TextLayout *) layout;
2234          fontPtr = (TkFont *) layoutPtr->tkfont;          fontPtr = (TkFont *) layoutPtr->tkfont;
2235    
2236          XFillRectangle(display, drawable, gc, x + xx,          XFillRectangle(display, drawable, gc, x + xx,
2237                  y + yy + fontPtr->fm.ascent + fontPtr->underlinePos,                  y + yy + fontPtr->fm.ascent + fontPtr->underlinePos,
2238                  (unsigned int) width, (unsigned int) fontPtr->underlineHeight);                  (unsigned int) width, (unsigned int) fontPtr->underlineHeight);
2239      }      }
2240  }  }
2241    
2242  /*  /*
2243   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2244   *   *
2245   * Tk_PointToChar --   * Tk_PointToChar --
2246   *   *
2247   *      Use the information in the Tk_TextLayout token to determine the   *      Use the information in the Tk_TextLayout token to determine the
2248   *      character closest to the given point.  The point must be   *      character closest to the given point.  The point must be
2249   *      specified with respect to the upper-left hand corner of the   *      specified with respect to the upper-left hand corner of the
2250   *      text layout, which is considered to be located at (0, 0).   *      text layout, which is considered to be located at (0, 0).
2251   *   *
2252   *      Any point whose y-value is less that 0 will be considered closest   *      Any point whose y-value is less that 0 will be considered closest
2253   *      to the first character in the text layout; any point whose y-value   *      to the first character in the text layout; any point whose y-value
2254   *      is greater than the height of the text layout will be considered   *      is greater than the height of the text layout will be considered
2255   *      closest to the last character in the text layout.   *      closest to the last character in the text layout.
2256   *   *
2257   *      Any point whose x-value is less than 0 will be considered closest   *      Any point whose x-value is less than 0 will be considered closest
2258   *      to the first character on that line; any point whose x-value is   *      to the first character on that line; any point whose x-value is
2259   *      greater than the width of the text layout will be considered   *      greater than the width of the text layout will be considered
2260   *      closest to the last character on that line.   *      closest to the last character on that line.
2261   *   *
2262   * Results:   * Results:
2263   *      The return value is the index of the character that was   *      The return value is the index of the character that was
2264   *      closest to the point.  Given a text layout with no characters,   *      closest to the point.  Given a text layout with no characters,
2265   *      the value 0 will always be returned, referring to a hypothetical   *      the value 0 will always be returned, referring to a hypothetical
2266   *      zero-width placeholder character.   *      zero-width placeholder character.
2267   *   *
2268   * Side effects:   * Side effects:
2269   *      None.   *      None.
2270   *   *
2271   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2272   */   */
2273    
2274  int  int
2275  Tk_PointToChar(layout, x, y)  Tk_PointToChar(layout, x, y)
2276      Tk_TextLayout layout;       /* Layout information, from a previous call      Tk_TextLayout layout;       /* Layout information, from a previous call
2277                                   * to Tk_ComputeTextLayout(). */                                   * to Tk_ComputeTextLayout(). */
2278      int x, y;                   /* Coordinates of point to check, with      int x, y;                   /* Coordinates of point to check, with
2279                                   * respect to the upper-left corner of the                                   * respect to the upper-left corner of the
2280                                   * text layout. */                                   * text layout. */
2281  {  {
2282      TextLayout *layoutPtr;      TextLayout *layoutPtr;
2283      LayoutChunk *chunkPtr, *lastPtr;      LayoutChunk *chunkPtr, *lastPtr;
2284      TkFont *fontPtr;      TkFont *fontPtr;
2285      int i, n, dummy, baseline, pos, numChars;      int i, n, dummy, baseline, pos, numChars;
2286    
2287      if (y < 0) {      if (y < 0) {
2288          /*          /*
2289           * Point lies above any line in this layout.  Return the index of           * Point lies above any line in this layout.  Return the index of
2290           * the first char.           * the first char.
2291           */           */
2292    
2293          return 0;          return 0;
2294      }      }
2295    
2296      /*      /*
2297       * Find which line contains the point.       * Find which line contains the point.
2298       */       */
2299    
2300      layoutPtr = (TextLayout *) layout;      layoutPtr = (TextLayout *) layout;
2301      fontPtr = (TkFont *) layoutPtr->tkfont;      fontPtr = (TkFont *) layoutPtr->tkfont;
2302      lastPtr = chunkPtr = layoutPtr->chunks;      lastPtr = chunkPtr = layoutPtr->chunks;
2303      numChars = 0;      numChars = 0;
2304      for (i = 0; i < layoutPtr->numChunks; i++) {      for (i = 0; i < layoutPtr->numChunks; i++) {
2305          baseline = chunkPtr->y;          baseline = chunkPtr->y;
2306          if (y < baseline + fontPtr->fm.descent) {          if (y < baseline + fontPtr->fm.descent) {
2307              if (x < chunkPtr->x) {              if (x < chunkPtr->x) {
2308                  /*                  /*
2309                   * Point is to the left of all chunks on this line.  Return                   * Point is to the left of all chunks on this line.  Return
2310                   * the index of the first character on this line.                   * the index of the first character on this line.
2311                   */                   */
2312    
2313                  return numChars;                  return numChars;
2314              }              }
2315              if (x >= layoutPtr->width) {              if (x >= layoutPtr->width) {
2316                  /*                  /*
2317                   * If point lies off right side of the text layout, return                   * If point lies off right side of the text layout, return
2318                   * the last char in the last chunk on this line.  Without                   * the last char in the last chunk on this line.  Without
2319                   * this, it might return the index of the first char that                   * this, it might return the index of the first char that
2320                   * was located outside of the text layout.                   * was located outside of the text layout.
2321                   */                   */
2322    
2323                  x = INT_MAX;                  x = INT_MAX;
2324              }              }
2325    
2326              /*              /*
2327               * Examine all chunks on this line to see which one contains               * Examine all chunks on this line to see which one contains
2328               * the specified point.               * the specified point.
2329               */               */
2330    
2331              lastPtr = chunkPtr;              lastPtr = chunkPtr;
2332              while ((i < layoutPtr->numChunks) && (chunkPtr->y == baseline))  {              while ((i < layoutPtr->numChunks) && (chunkPtr->y == baseline))  {
2333                  if (x < chunkPtr->x + chunkPtr->totalWidth) {                  if (x < chunkPtr->x + chunkPtr->totalWidth) {
2334                      /*                      /*
2335                       * Point falls on one of the characters in this chunk.                       * Point falls on one of the characters in this chunk.
2336                       */                       */
2337    
2338                      if (chunkPtr->numDisplayChars < 0) {                      if (chunkPtr->numDisplayChars < 0) {
2339                          /*                          /*
2340                           * This is a special chunk that encapsulates a single                           * This is a special chunk that encapsulates a single
2341                           * tab or newline char.                           * tab or newline char.
2342                           */                           */
2343    
2344                          return numChars;                          return numChars;
2345                      }                      }
2346                      n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start,                      n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start,
2347                              chunkPtr->numBytes, x - chunkPtr->x,                              chunkPtr->numBytes, x - chunkPtr->x,
2348                              0, &dummy);                              0, &dummy);
2349                      return numChars + Tcl_NumUtfChars(chunkPtr->start, n);                      return numChars + Tcl_NumUtfChars(chunkPtr->start, n);
2350                  }                  }
2351                  numChars += chunkPtr->numChars;                  numChars += chunkPtr->numChars;
2352                  lastPtr = chunkPtr;                  lastPtr = chunkPtr;
2353                  chunkPtr++;                  chunkPtr++;
2354                  i++;                  i++;
2355              }              }
2356    
2357              /*              /*
2358               * Point is to the right of all chars in all the chunks on this               * Point is to the right of all chars in all the chunks on this
2359               * line.  Return the index just past the last char in the last               * line.  Return the index just past the last char in the last
2360               * chunk on this line.               * chunk on this line.
2361               */               */
2362    
2363              pos = numChars;              pos = numChars;
2364              if (i < layoutPtr->numChunks) {              if (i < layoutPtr->numChunks) {
2365                  pos--;                  pos--;
2366              }              }
2367              return pos;              return pos;
2368          }          }
2369          numChars += chunkPtr->numChars;          numChars += chunkPtr->numChars;
2370          lastPtr = chunkPtr;          lastPtr = chunkPtr;
2371          chunkPtr++;          chunkPtr++;
2372      }      }
2373    
2374      /*      /*
2375       * Point lies below any line in this text layout.  Return the index       * Point lies below any line in this text layout.  Return the index
2376       * just past the last char.       * just past the last char.
2377       */       */
2378    
2379      return (lastPtr->start + lastPtr->numChars) - layoutPtr->string;      return (lastPtr->start + lastPtr->numChars) - layoutPtr->string;
2380  }  }
2381    
2382  /*  /*
2383   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2384   *   *
2385   * Tk_CharBbox --   * Tk_CharBbox --
2386   *   *
2387   *      Use the information in the Tk_TextLayout token to return the   *      Use the information in the Tk_TextLayout token to return the
2388   *      bounding box for the character specified by index.     *      bounding box for the character specified by index.  
2389   *   *
2390   *      The width of the bounding box is the advance width of the   *      The width of the bounding box is the advance width of the
2391   *      character, and does not include and left- or right-bearing.   *      character, and does not include and left- or right-bearing.
2392   *      Any character that extends partially outside of the   *      Any character that extends partially outside of the
2393   *      text layout is considered to be truncated at the edge.  Any   *      text layout is considered to be truncated at the edge.  Any
2394   *      character which is located completely outside of the text   *      character which is located completely outside of the text
2395   *      layout is considered to be zero-width and pegged against   *      layout is considered to be zero-width and pegged against
2396   *      the edge.   *      the edge.
2397   *   *
2398   *      The height of the bounding box is the line height for this font,   *      The height of the bounding box is the line height for this font,
2399   *      extending from the top of the ascent to the bottom of the   *      extending from the top of the ascent to the bottom of the
2400   *      descent.  Information about the actual height of the individual   *      descent.  Information about the actual height of the individual
2401   *      letter is not available.   *      letter is not available.
2402   *   *
2403   *      A text layout that contains no characters is considered to   *      A text layout that contains no characters is considered to
2404   *      contain a single zero-width placeholder character.   *      contain a single zero-width placeholder character.
2405   *   *
2406   * Results:   * Results:
2407   *      The return value is 0 if the index did not specify a character   *      The return value is 0 if the index did not specify a character
2408   *      in the text layout, or non-zero otherwise.  In that case,   *      in the text layout, or non-zero otherwise.  In that case,
2409   *      *bbox is filled with the bounding box of the character.   *      *bbox is filled with the bounding box of the character.
2410   *   *
2411   * Side effects:   * Side effects:
2412   *      None.   *      None.
2413   *   *
2414   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2415   */   */
2416    
2417  int  int
2418  Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr)  Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr)
2419      Tk_TextLayout layout;   /* Layout information, from a previous call to      Tk_TextLayout layout;   /* Layout information, from a previous call to
2420                               * Tk_ComputeTextLayout(). */                               * Tk_ComputeTextLayout(). */
2421      int index;              /* The index of the character whose bbox is      int index;              /* The index of the character whose bbox is
2422                               * desired. */                               * desired. */
2423      int *xPtr, *yPtr;       /* Filled with the upper-left hand corner, in      int *xPtr, *yPtr;       /* Filled with the upper-left hand corner, in
2424                               * pixels, of the bounding box for the character                               * pixels, of the bounding box for the character
2425                               * specified by index, if non-NULL. */                               * specified by index, if non-NULL. */
2426      int *widthPtr, *heightPtr;      int *widthPtr, *heightPtr;
2427                              /* Filled with the width and height of the                              /* Filled with the width and height of the
2428                               * bounding box for the character specified by                               * bounding box for the character specified by
2429                               * index, if non-NULL. */                               * index, if non-NULL. */
2430  {  {
2431      TextLayout *layoutPtr;      TextLayout *layoutPtr;
2432      LayoutChunk *chunkPtr;      LayoutChunk *chunkPtr;
2433      int i, x, w;      int i, x, w;
2434      Tk_Font tkfont;      Tk_Font tkfont;
2435      TkFont *fontPtr;      TkFont *fontPtr;
2436      CONST char *end;      CONST char *end;
2437    
2438      if (index < 0) {      if (index < 0) {
2439          return 0;          return 0;
2440      }      }
2441    
2442      layoutPtr = (TextLayout *) layout;      layoutPtr = (TextLayout *) layout;
2443      chunkPtr = layoutPtr->chunks;      chunkPtr = layoutPtr->chunks;
2444      tkfont = layoutPtr->tkfont;      tkfont = layoutPtr->tkfont;
2445      fontPtr = (TkFont *) tkfont;      fontPtr = (TkFont *) tkfont;
2446    
2447      for (i = 0; i < layoutPtr->numChunks; i++) {      for (i = 0; i < layoutPtr->numChunks; i++) {
2448          if (chunkPtr->numDisplayChars < 0) {          if (chunkPtr->numDisplayChars < 0) {
2449              if (index == 0) {              if (index == 0) {
2450                  x = chunkPtr->x;                  x = chunkPtr->x;
2451                  w = chunkPtr->totalWidth;                  w = chunkPtr->totalWidth;
2452                  goto check;                  goto check;
2453              }              }
2454          } else if (index < chunkPtr->numChars) {          } else if (index < chunkPtr->numChars) {
2455              end = Tcl_UtfAtIndex(chunkPtr->start, index);              end = Tcl_UtfAtIndex(chunkPtr->start, index);
2456              if (xPtr != NULL) {              if (xPtr != NULL) {
2457                  Tk_MeasureChars(tkfont, chunkPtr->start,                  Tk_MeasureChars(tkfont, chunkPtr->start,
2458                          end -  chunkPtr->start, -1, 0, &x);                          end -  chunkPtr->start, -1, 0, &x);
2459                  x += chunkPtr->x;                  x += chunkPtr->x;
2460              }              }
2461              if (widthPtr != NULL) {              if (widthPtr != NULL) {
2462                  Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end,                  Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end,
2463                          -1, 0, &w);                          -1, 0, &w);
2464              }              }
2465              goto check;              goto check;
2466          }          }
2467          index -= chunkPtr->numChars;          index -= chunkPtr->numChars;
2468          chunkPtr++;          chunkPtr++;
2469      }      }
2470      if (index == 0) {      if (index == 0) {
2471          /*          /*
2472           * Special case to get location just past last char in layout.           * Special case to get location just past last char in layout.
2473           */           */
2474    
2475          chunkPtr--;          chunkPtr--;
2476          x = chunkPtr->x + chunkPtr->totalWidth;          x = chunkPtr->x + chunkPtr->totalWidth;
2477          w = 0;          w = 0;
2478      } else {      } else {
2479          return 0;          return 0;
2480      }      }
2481    
2482      /*      /*
2483       * Ensure that the bbox lies within the text layout.  This forces all       * Ensure that the bbox lies within the text layout.  This forces all
2484       * chars that extend off the right edge of the text layout to have       * chars that extend off the right edge of the text layout to have
2485       * truncated widths, and all chars that are completely off the right       * truncated widths, and all chars that are completely off the right
2486       * edge of the text layout to peg to the edge and have 0 width.       * edge of the text layout to peg to the edge and have 0 width.
2487       */       */
2488      check:      check:
2489      if (yPtr != NULL) {      if (yPtr != NULL) {
2490          *yPtr = chunkPtr->y - fontPtr->fm.ascent;          *yPtr = chunkPtr->y - fontPtr->fm.ascent;
2491      }      }
2492      if (heightPtr != NULL) {      if (heightPtr != NULL) {
2493          *heightPtr = fontPtr->fm.ascent + fontPtr->fm.descent;          *heightPtr = fontPtr->fm.ascent + fontPtr->fm.descent;
2494      }      }
2495    
2496      if (x > layoutPtr->width) {      if (x > layoutPtr->width) {
2497          x = layoutPtr->width;          x = layoutPtr->width;
2498      }      }
2499      if (xPtr != NULL) {      if (xPtr != NULL) {
2500          *xPtr = x;          *xPtr = x;
2501      }      }
2502      if (widthPtr != NULL) {      if (widthPtr != NULL) {
2503          if (x + w > layoutPtr->width) {          if (x + w > layoutPtr->width) {
2504              w = layoutPtr->width - x;              w = layoutPtr->width - x;
2505          }          }
2506          *widthPtr = w;          *widthPtr = w;
2507      }      }
2508    
2509      return 1;      return 1;
2510  }  }
2511    
2512  /*  /*
2513   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2514   *   *
2515   * Tk_DistanceToTextLayout --   * Tk_DistanceToTextLayout --
2516   *   *
2517   *      Computes the distance in pixels from the given point to the   *      Computes the distance in pixels from the given point to the
2518   *      given text layout.  Non-displaying space characters that occur   *      given text layout.  Non-displaying space characters that occur
2519   *      at the end of individual lines in the text layout are ignored   *      at the end of individual lines in the text layout are ignored
2520   *      for hit detection purposes.   *      for hit detection purposes.
2521   *   *
2522   * Results:   * Results:
2523   *      The return value is 0 if the point (x, y) is inside the text   *      The return value is 0 if the point (x, y) is inside the text
2524   *      layout.  If the point isn't inside the text layout then the   *      layout.  If the point isn't inside the text layout then the
2525   *      return value is the distance in pixels from the point to the   *      return value is the distance in pixels from the point to the
2526   *      text item.   *      text item.
2527   *   *
2528   * Side effects:   * Side effects:
2529   *      None.   *      None.
2530   *   *
2531   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2532   */   */
2533    
2534  int  int
2535  Tk_DistanceToTextLayout(layout, x, y)  Tk_DistanceToTextLayout(layout, x, y)
2536      Tk_TextLayout layout;       /* Layout information, from a previous call      Tk_TextLayout layout;       /* Layout information, from a previous call
2537                                   * to Tk_ComputeTextLayout(). */                                   * to Tk_ComputeTextLayout(). */
2538      int x, y;                   /* Coordinates of point to check, with      int x, y;                   /* Coordinates of point to check, with
2539                                   * respect to the upper-left corner of the                                   * respect to the upper-left corner of the
2540                                   * text layout (in pixels). */                                   * text layout (in pixels). */
2541  {  {
2542      int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;      int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;
2543      LayoutChunk *chunkPtr;      LayoutChunk *chunkPtr;
2544      TextLayout *layoutPtr;      TextLayout *layoutPtr;
2545      TkFont *fontPtr;      TkFont *fontPtr;
2546    
2547      layoutPtr = (TextLayout *) layout;      layoutPtr = (TextLayout *) layout;
2548      fontPtr = (TkFont *) layoutPtr->tkfont;      fontPtr = (TkFont *) layoutPtr->tkfont;
2549      ascent = fontPtr->fm.ascent;      ascent = fontPtr->fm.ascent;
2550      descent = fontPtr->fm.descent;      descent = fontPtr->fm.descent;
2551            
2552      minDist = 0;      minDist = 0;
2553      chunkPtr = layoutPtr->chunks;      chunkPtr = layoutPtr->chunks;
2554      for (i = 0; i < layoutPtr->numChunks; i++) {      for (i = 0; i < layoutPtr->numChunks; i++) {
2555          if (chunkPtr->start[0] == '\n') {          if (chunkPtr->start[0] == '\n') {
2556              /*              /*
2557               * Newline characters are not counted when computing distance               * Newline characters are not counted when computing distance
2558               * (but tab characters would still be considered).               * (but tab characters would still be considered).
2559               */               */
2560    
2561              chunkPtr++;              chunkPtr++;
2562              continue;              continue;
2563          }          }
2564    
2565          x1 = chunkPtr->x;          x1 = chunkPtr->x;
2566          y1 = chunkPtr->y - ascent;          y1 = chunkPtr->y - ascent;
2567          x2 = chunkPtr->x + chunkPtr->displayWidth;          x2 = chunkPtr->x + chunkPtr->displayWidth;
2568          y2 = chunkPtr->y + descent;          y2 = chunkPtr->y + descent;
2569    
2570          if (x < x1) {          if (x < x1) {
2571              xDiff = x1 - x;              xDiff = x1 - x;
2572          } else if (x >= x2) {          } else if (x >= x2) {
2573              xDiff = x - x2 + 1;              xDiff = x - x2 + 1;
2574          } else {          } else {
2575              xDiff = 0;              xDiff = 0;
2576          }          }
2577    
2578          if (y < y1) {          if (y < y1) {
2579              yDiff = y1 - y;              yDiff = y1 - y;
2580          } else if (y >= y2) {          } else if (y >= y2) {
2581              yDiff = y - y2 + 1;              yDiff = y - y2 + 1;
2582          } else {          } else {
2583              yDiff = 0;              yDiff = 0;
2584          }          }
2585          if ((xDiff == 0) && (yDiff == 0)) {          if ((xDiff == 0) && (yDiff == 0)) {
2586              return 0;              return 0;
2587          }          }
2588          dist = (int) hypot((double) xDiff, (double) yDiff);          dist = (int) hypot((double) xDiff, (double) yDiff);
2589          if ((dist < minDist) || (minDist == 0)) {          if ((dist < minDist) || (minDist == 0)) {
2590              minDist = dist;              minDist = dist;
2591          }          }
2592          chunkPtr++;          chunkPtr++;
2593      }      }
2594      return minDist;      return minDist;
2595  }  }
2596    
2597  /*  /*
2598   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2599   *   *
2600   * Tk_IntersectTextLayout --   * Tk_IntersectTextLayout --
2601   *   *
2602   *      Determines whether a text layout lies entirely inside,   *      Determines whether a text layout lies entirely inside,
2603   *      entirely outside, or overlaps a given rectangle.  Non-displaying   *      entirely outside, or overlaps a given rectangle.  Non-displaying
2604   *      space characters that occur at the end of individual lines in   *      space characters that occur at the end of individual lines in
2605   *      the text layout are ignored for intersection calculations.   *      the text layout are ignored for intersection calculations.
2606   *   *
2607   * Results:   * Results:
2608   *      The return value is -1 if the text layout is entirely outside of   *      The return value is -1 if the text layout is entirely outside of
2609   *      the rectangle, 0 if it overlaps, and 1 if it is entirely inside   *      the rectangle, 0 if it overlaps, and 1 if it is entirely inside
2610   *      of the rectangle.   *      of the rectangle.
2611   *   *
2612   * Side effects:   * Side effects:
2613   *      None.   *      None.
2614   *   *
2615   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2616   */   */
2617    
2618  int  int
2619  Tk_IntersectTextLayout(layout, x, y, width, height)  Tk_IntersectTextLayout(layout, x, y, width, height)
2620      Tk_TextLayout layout;       /* Layout information, from a previous call      Tk_TextLayout layout;       /* Layout information, from a previous call
2621                                   * to Tk_ComputeTextLayout(). */                                   * to Tk_ComputeTextLayout(). */
2622      int x, y;                   /* Upper-left hand corner, in pixels, of      int x, y;                   /* Upper-left hand corner, in pixels, of
2623                                   * rectangular area to compare with text                                   * rectangular area to compare with text
2624                                   * layout.  Coordinates are with respect to                                   * layout.  Coordinates are with respect to
2625                                   * the upper-left hand corner of the text                                   * the upper-left hand corner of the text
2626                                   * layout itself. */                                   * layout itself. */
2627      int width, height;          /* The width and height of the above      int width, height;          /* The width and height of the above
2628                                   * rectangular area, in pixels. */                                   * rectangular area, in pixels. */
2629  {  {
2630      int result, i, x1, y1, x2, y2;      int result, i, x1, y1, x2, y2;
2631      TextLayout *layoutPtr;      TextLayout *layoutPtr;
2632      LayoutChunk *chunkPtr;      LayoutChunk *chunkPtr;
2633      TkFont *fontPtr;      TkFont *fontPtr;
2634      int left, top, right, bottom;      int left, top, right, bottom;
2635    
2636      /*      /*
2637       * Scan the chunks one at a time, seeing whether each is entirely in,       * Scan the chunks one at a time, seeing whether each is entirely in,
2638       * entirely out, or overlapping the rectangle.  If an overlap is       * entirely out, or overlapping the rectangle.  If an overlap is
2639       * detected, return immediately; otherwise wait until all chunks have       * detected, return immediately; otherwise wait until all chunks have
2640       * been processed and see if they were all inside or all outside.       * been processed and see if they were all inside or all outside.
2641       */       */
2642            
2643      layoutPtr = (TextLayout *) layout;      layoutPtr = (TextLayout *) layout;
2644      chunkPtr = layoutPtr->chunks;      chunkPtr = layoutPtr->chunks;
2645      fontPtr = (TkFont *) layoutPtr->tkfont;      fontPtr = (TkFont *) layoutPtr->tkfont;
2646    
2647      left    = x;      left    = x;
2648      top     = y;      top     = y;
2649      right   = x + width;      right   = x + width;
2650      bottom  = y + height;      bottom  = y + height;
2651    
2652      result = 0;      result = 0;
2653      for (i = 0; i < layoutPtr->numChunks; i++) {      for (i = 0; i < layoutPtr->numChunks; i++) {
2654          if (chunkPtr->start[0] == '\n') {          if (chunkPtr->start[0] == '\n') {
2655              /*              /*
2656               * Newline characters are not counted when computing area               * Newline characters are not counted when computing area
2657               * intersection (but tab characters would still be considered).               * intersection (but tab characters would still be considered).
2658               */               */
2659    
2660              chunkPtr++;              chunkPtr++;
2661              continue;              continue;
2662          }          }
2663    
2664          x1 = chunkPtr->x;          x1 = chunkPtr->x;
2665          y1 = chunkPtr->y - fontPtr->fm.ascent;          y1 = chunkPtr->y - fontPtr->fm.ascent;
2666          x2 = chunkPtr->x + chunkPtr->displayWidth;          x2 = chunkPtr->x + chunkPtr->displayWidth;
2667          y2 = chunkPtr->y + fontPtr->fm.descent;          y2 = chunkPtr->y + fontPtr->fm.descent;
2668    
2669          if ((right < x1) || (left >= x2)          if ((right < x1) || (left >= x2)
2670                  || (bottom < y1) || (top >= y2)) {                  || (bottom < y1) || (top >= y2)) {
2671              if (result == 1) {              if (result == 1) {
2672                  return 0;                  return 0;
2673              }              }
2674              result = -1;              result = -1;
2675          } else if ((x1 < left) || (x2 >= right)          } else if ((x1 < left) || (x2 >= right)
2676                  || (y1 < top) || (y2 >= bottom)) {                  || (y1 < top) || (y2 >= bottom)) {
2677              return 0;              return 0;
2678          } else if (result == -1) {          } else if (result == -1) {
2679              return 0;              return 0;
2680          } else {          } else {
2681              result = 1;              result = 1;
2682          }          }
2683          chunkPtr++;          chunkPtr++;
2684      }      }
2685      return result;      return result;
2686  }  }
2687    
2688  /*  /*
2689   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2690   *   *
2691   * Tk_TextLayoutToPostscript --   * Tk_TextLayoutToPostscript --
2692   *   *
2693   *      Outputs the contents of a text layout in Postscript format.   *      Outputs the contents of a text layout in Postscript format.
2694   *      The set of lines in the text layout will be rendered by the user   *      The set of lines in the text layout will be rendered by the user
2695   *      supplied Postscript function.  The function should be of the form:   *      supplied Postscript function.  The function should be of the form:
2696   *   *
2697   *          justify x y string  function  --   *          justify x y string  function  --
2698   *   *
2699   *      Justify is -1, 0, or 1, depending on whether the following string   *      Justify is -1, 0, or 1, depending on whether the following string
2700   *      should be left, center, or right justified, x and y is the   *      should be left, center, or right justified, x and y is the
2701   *      location for the origin of the string, string is the sequence   *      location for the origin of the string, string is the sequence
2702   *      of characters to be printed, and function is the name of the   *      of characters to be printed, and function is the name of the
2703   *      caller-provided function; the function should leave nothing   *      caller-provided function; the function should leave nothing
2704   *      on the stack.   *      on the stack.
2705   *   *
2706   *      The meaning of the origin of the string (x and y) depends on   *      The meaning of the origin of the string (x and y) depends on
2707   *      the justification.  For left justification, x is where the   *      the justification.  For left justification, x is where the
2708   *      left edge of the string should appear.  For center justification,   *      left edge of the string should appear.  For center justification,
2709   *      x is where the center of the string should appear.  And for right   *      x is where the center of the string should appear.  And for right
2710   *      justification, x is where the right edge of the string should   *      justification, x is where the right edge of the string should
2711   *      appear.  This behavior is necessary because, for example, right   *      appear.  This behavior is necessary because, for example, right
2712   *      justified text on the screen is justified with screen metrics.   *      justified text on the screen is justified with screen metrics.
2713   *      The same string needs to be justified with printer metrics on   *      The same string needs to be justified with printer metrics on
2714   *      the printer to appear in the correct place with respect to other   *      the printer to appear in the correct place with respect to other
2715   *      similarly justified strings.  In all circumstances, y is the   *      similarly justified strings.  In all circumstances, y is the
2716   *      location of the baseline for the string.   *      location of the baseline for the string.
2717   *   *
2718   * Results:   * Results:
2719   *      The interp's result is modified to hold the Postscript code that   *      The interp's result is modified to hold the Postscript code that
2720   *      will render the text layout.   *      will render the text layout.
2721   *   *
2722   * Side effects:   * Side effects:
2723   *      None.   *      None.
2724   *   *
2725   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2726   */   */
2727    
2728  void  void
2729  Tk_TextLayoutToPostscript(interp, layout)  Tk_TextLayoutToPostscript(interp, layout)
2730      Tcl_Interp *interp;         /* Filled with Postscript code. */      Tcl_Interp *interp;         /* Filled with Postscript code. */
2731      Tk_TextLayout layout;       /* The layout to be rendered. */      Tk_TextLayout layout;       /* The layout to be rendered. */
2732  {  {
2733  #define MAXUSE 128  #define MAXUSE 128
2734      char buf[MAXUSE+10];      char buf[MAXUSE+10];
2735      LayoutChunk *chunkPtr;      LayoutChunk *chunkPtr;
2736      int i, j, used, c, baseline;      int i, j, used, c, baseline;
2737      Tcl_UniChar ch;      Tcl_UniChar ch;
2738      CONST char *p;      CONST char *p;
2739      TextLayout *layoutPtr;      TextLayout *layoutPtr;
2740    
2741      layoutPtr = (TextLayout *) layout;      layoutPtr = (TextLayout *) layout;
2742      chunkPtr = layoutPtr->chunks;      chunkPtr = layoutPtr->chunks;
2743      baseline = chunkPtr->y;      baseline = chunkPtr->y;
2744      used = 0;      used = 0;
2745      buf[used++] = '(';      buf[used++] = '(';
2746      for (i = 0; i < layoutPtr->numChunks; i++) {      for (i = 0; i < layoutPtr->numChunks; i++) {
2747          if (baseline != chunkPtr->y) {          if (baseline != chunkPtr->y) {
2748              buf[used++] = ')';              buf[used++] = ')';
2749              buf[used++] = '\n';              buf[used++] = '\n';
2750              buf[used++] = '(';              buf[used++] = '(';
2751              baseline = chunkPtr->y;              baseline = chunkPtr->y;
2752          }          }
2753          if (chunkPtr->numDisplayChars <= 0) {          if (chunkPtr->numDisplayChars <= 0) {
2754              if (chunkPtr->start[0] == '\t') {              if (chunkPtr->start[0] == '\t') {
2755                  buf[used++] = '\\';                  buf[used++] = '\\';
2756                  buf[used++] = 't';                  buf[used++] = 't';
2757              }              }
2758          } else {          } else {
2759              p = chunkPtr->start;              p = chunkPtr->start;
2760              for (j = 0; j < chunkPtr->numDisplayChars; j++) {              for (j = 0; j < chunkPtr->numDisplayChars; j++) {
2761                  /*                  /*
2762                   * INTL: For now we just treat the characters as binary                   * INTL: For now we just treat the characters as binary
2763                   * data and display the lower byte.  Eventually this should                   * data and display the lower byte.  Eventually this should
2764                   * be revised to handle international postscript fonts.                   * be revised to handle international postscript fonts.
2765                   */                   */
2766    
2767                  p += Tcl_UtfToUniChar(p, &ch);                  p += Tcl_UtfToUniChar(p, &ch);
2768                  c = UCHAR(ch & 0xff);                  c = UCHAR(ch & 0xff);
2769                  if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20)                  if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20)
2770                          || (c >= UCHAR(0x7f))) {                          || (c >= UCHAR(0x7f))) {
2771                      /*                      /*
2772                       * Tricky point:  the "03" is necessary in the sprintf                       * Tricky point:  the "03" is necessary in the sprintf
2773                       * below, so that a full three digits of octal are                       * below, so that a full three digits of octal are
2774                       * always generated.  Without the "03", a number                       * always generated.  Without the "03", a number
2775                       * following this sequence could be interpreted by                       * following this sequence could be interpreted by
2776                       * Postscript as part of this sequence.                       * Postscript as part of this sequence.
2777                       */                       */
2778    
2779                      sprintf(buf + used, "\\%03o", c);                      sprintf(buf + used, "\\%03o", c);
2780                      used += 4;                      used += 4;
2781                  } else {                  } else {
2782                      buf[used++] = c;                      buf[used++] = c;
2783                  }                  }
2784                  if (used >= MAXUSE) {                  if (used >= MAXUSE) {
2785                      buf[used] = '\0';                      buf[used] = '\0';
2786                      Tcl_AppendResult(interp, buf, (char *) NULL);                      Tcl_AppendResult(interp, buf, (char *) NULL);
2787                      used = 0;                      used = 0;
2788                  }                  }
2789              }              }
2790          }          }
2791          if (used >= MAXUSE) {          if (used >= MAXUSE) {
2792              /*              /*
2793               * If there are a whole bunch of returns or tabs in a row,               * If there are a whole bunch of returns or tabs in a row,
2794               * then buf[] could get filled up.               * then buf[] could get filled up.
2795               */               */
2796                            
2797              buf[used] = '\0';              buf[used] = '\0';
2798              Tcl_AppendResult(interp, buf, (char *) NULL);              Tcl_AppendResult(interp, buf, (char *) NULL);
2799              used = 0;              used = 0;
2800          }          }
2801          chunkPtr++;          chunkPtr++;
2802      }      }
2803      buf[used++] = ')';      buf[used++] = ')';
2804      buf[used++] = '\n';      buf[used++] = '\n';
2805      buf[used] = '\0';      buf[used] = '\0';
2806      Tcl_AppendResult(interp, buf, (char *) NULL);      Tcl_AppendResult(interp, buf, (char *) NULL);
2807  }  }
2808    
2809  /*  /*
2810   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2811   *   *
2812   * ConfigAttributesObj --   * ConfigAttributesObj --
2813   *   *
2814   *      Process command line options to fill in fields of a properly   *      Process command line options to fill in fields of a properly
2815   *      initialized font attributes structure.   *      initialized font attributes structure.
2816   *   *
2817   * Results:   * Results:
2818   *      A standard Tcl return value.  If TCL_ERROR is returned, an   *      A standard Tcl return value.  If TCL_ERROR is returned, an
2819   *      error message will be left in interp's result object.   *      error message will be left in interp's result object.
2820   *   *
2821   * Side effects:   * Side effects:
2822   *      The fields of the font attributes structure get filled in with   *      The fields of the font attributes structure get filled in with
2823   *      information from argc/argv.  If an error occurs while parsing,   *      information from argc/argv.  If an error occurs while parsing,
2824   *      the font attributes structure will contain all modifications   *      the font attributes structure will contain all modifications
2825   *      specified in the command line options up to the point of the   *      specified in the command line options up to the point of the
2826   *      error.   *      error.
2827   *   *
2828   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2829   */   */
2830    
2831  static int  static int
2832  ConfigAttributesObj(interp, tkwin, objc, objv, faPtr)  ConfigAttributesObj(interp, tkwin, objc, objv, faPtr)
2833      Tcl_Interp *interp;         /* Interp for error return. */      Tcl_Interp *interp;         /* Interp for error return. */
2834      Tk_Window tkwin;            /* For display on which font will be used. */      Tk_Window tkwin;            /* For display on which font will be used. */
2835      int objc;                   /* Number of elements in argv. */      int objc;                   /* Number of elements in argv. */
2836      Tcl_Obj *CONST objv[];      /* Command line options. */      Tcl_Obj *CONST objv[];      /* Command line options. */
2837      TkFontAttributes *faPtr;    /* Font attributes structure whose fields      TkFontAttributes *faPtr;    /* Font attributes structure whose fields
2838                                   * are to be modified.  Structure must already                                   * are to be modified.  Structure must already
2839                                   * be properly initialized. */                                   * be properly initialized. */
2840  {  {
2841      int i, n, index;      int i, n, index;
2842      Tcl_Obj *optionPtr, *valuePtr;      Tcl_Obj *optionPtr, *valuePtr;
2843      char *value;      char *value;
2844            
2845      for (i = 0; i < objc; i += 2) {      for (i = 0; i < objc; i += 2) {
2846          optionPtr = objv[i];          optionPtr = objv[i];
2847          valuePtr = objv[i + 1];          valuePtr = objv[i + 1];
2848    
2849          if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1,          if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1,
2850                  &index) != TCL_OK) {                  &index) != TCL_OK) {
2851              return TCL_ERROR;              return TCL_ERROR;
2852          }          }
2853          if ((i+2 >= objc) && (objc & 1)) {          if ((i+2 >= objc) && (objc & 1)) {
2854              /*              /*
2855               * This test occurs after Tcl_GetIndexFromObj() so that               * This test occurs after Tcl_GetIndexFromObj() so that
2856               * "font create xyz -xyz" will return the error message               * "font create xyz -xyz" will return the error message
2857               * that "-xyz" is a bad option, rather than that the value               * that "-xyz" is a bad option, rather than that the value
2858               * for "-xyz" is missing.               * for "-xyz" is missing.
2859               */               */
2860    
2861              Tcl_AppendResult(interp, "value for \"",              Tcl_AppendResult(interp, "value for \"",
2862                      Tcl_GetString(optionPtr), "\" option missing",                      Tcl_GetString(optionPtr), "\" option missing",
2863                      (char *) NULL);                      (char *) NULL);
2864              return TCL_ERROR;              return TCL_ERROR;
2865          }          }
2866    
2867          switch (index) {          switch (index) {
2868              case FONT_FAMILY: {              case FONT_FAMILY: {
2869                  value = Tcl_GetString(valuePtr);                  value = Tcl_GetString(valuePtr);
2870                  faPtr->family = Tk_GetUid(value);                  faPtr->family = Tk_GetUid(value);
2871                  break;                  break;
2872              }              }
2873              case FONT_SIZE: {              case FONT_SIZE: {
2874                  if (Tcl_GetIntFromObj(interp, valuePtr, &n) != TCL_OK) {                  if (Tcl_GetIntFromObj(interp, valuePtr, &n) != TCL_OK) {
2875                      return TCL_ERROR;                      return TCL_ERROR;
2876                  }                  }
2877                  faPtr->size = n;                  faPtr->size = n;
2878                  break;                  break;
2879              }              }
2880              case FONT_WEIGHT: {              case FONT_WEIGHT: {
2881                  n = TkFindStateNumObj(interp, optionPtr, weightMap, valuePtr);                  n = TkFindStateNumObj(interp, optionPtr, weightMap, valuePtr);
2882                  if (n == TK_FW_UNKNOWN) {                  if (n == TK_FW_UNKNOWN) {
2883                      return TCL_ERROR;                      return TCL_ERROR;
2884                  }                  }
2885                  faPtr->weight = n;                  faPtr->weight = n;
2886                  break;                  break;
2887              }              }
2888              case FONT_SLANT: {              case FONT_SLANT: {
2889                  n = TkFindStateNumObj(interp, optionPtr, slantMap, valuePtr);                  n = TkFindStateNumObj(interp, optionPtr, slantMap, valuePtr);
2890                  if (n == TK_FS_UNKNOWN) {                  if (n == TK_FS_UNKNOWN) {
2891                      return TCL_ERROR;                      return TCL_ERROR;
2892                  }                  }
2893                  faPtr->slant = n;                  faPtr->slant = n;
2894                  break;                  break;
2895              }              }
2896              case FONT_UNDERLINE: {              case FONT_UNDERLINE: {
2897                  if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) {                  if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) {
2898                      return TCL_ERROR;                      return TCL_ERROR;
2899                  }                  }
2900                  faPtr->underline = n;                  faPtr->underline = n;
2901                  break;                  break;
2902              }              }
2903              case FONT_OVERSTRIKE: {              case FONT_OVERSTRIKE: {
2904                  if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) {                  if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) {
2905                      return TCL_ERROR;                      return TCL_ERROR;
2906                  }                  }
2907                  faPtr->overstrike = n;                  faPtr->overstrike = n;
2908                  break;                  break;
2909              }              }
2910          }          }
2911      }      }
2912      return TCL_OK;      return TCL_OK;
2913  }  }
2914    
2915  /*  /*
2916   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2917   *   *
2918   * GetAttributeInfoObj --   * GetAttributeInfoObj --
2919   *   *
2920   *      Return information about the font attributes as a Tcl list.   *      Return information about the font attributes as a Tcl list.
2921   *   *
2922   * Results:   * Results:
2923   *      The return value is TCL_OK if the objPtr was non-NULL and   *      The return value is TCL_OK if the objPtr was non-NULL and
2924   *      specified a valid font attribute, TCL_ERROR otherwise.  If TCL_OK   *      specified a valid font attribute, TCL_ERROR otherwise.  If TCL_OK
2925   *      is returned, the interp's result object is modified to hold a   *      is returned, the interp's result object is modified to hold a
2926   *      description of either the current value of a single option, or a   *      description of either the current value of a single option, or a
2927   *      list of all options and their current values for the given font   *      list of all options and their current values for the given font
2928   *      attributes.  If TCL_ERROR is returned, the interp's result is   *      attributes.  If TCL_ERROR is returned, the interp's result is
2929   *      set to an error message describing that the objPtr did not refer   *      set to an error message describing that the objPtr did not refer
2930   *      to a valid option.   *      to a valid option.
2931   *   *
2932   * Side effects:   * Side effects:
2933   *      None.   *      None.
2934   *   *
2935   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2936   */   */
2937    
2938  static int  static int
2939  GetAttributeInfoObj(interp, faPtr, objPtr)  GetAttributeInfoObj(interp, faPtr, objPtr)
2940      Tcl_Interp *interp;                 /* Interp to hold result. */      Tcl_Interp *interp;                 /* Interp to hold result. */
2941      CONST TkFontAttributes *faPtr;      /* The font attributes to inspect. */      CONST TkFontAttributes *faPtr;      /* The font attributes to inspect. */
2942      Tcl_Obj *objPtr;                    /* If non-NULL, indicates the single      Tcl_Obj *objPtr;                    /* If non-NULL, indicates the single
2943                                           * option whose value is to be                                           * option whose value is to be
2944                                           * returned. Otherwise information is                                           * returned. Otherwise information is
2945                                           * returned for all options. */                                           * returned for all options. */
2946  {  {
2947      int i, index, start, end;      int i, index, start, end;
2948      char *str;      char *str;
2949      Tcl_Obj *optionPtr, *valuePtr, *resultPtr;      Tcl_Obj *optionPtr, *valuePtr, *resultPtr;
2950    
2951      resultPtr = Tcl_GetObjResult(interp);      resultPtr = Tcl_GetObjResult(interp);
2952    
2953      start = 0;      start = 0;
2954      end = FONT_NUMFIELDS;      end = FONT_NUMFIELDS;
2955      if (objPtr != NULL) {      if (objPtr != NULL) {
2956          if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", TCL_EXACT,          if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", TCL_EXACT,
2957                  &index) != TCL_OK) {                  &index) != TCL_OK) {
2958              return TCL_ERROR;              return TCL_ERROR;
2959          }          }
2960          start = index;          start = index;
2961          end = index + 1;          end = index + 1;
2962      }      }
2963    
2964      valuePtr = NULL;      valuePtr = NULL;
2965      for (i = start; i < end; i++) {      for (i = start; i < end; i++) {
2966          switch (i) {          switch (i) {
2967              case FONT_FAMILY:              case FONT_FAMILY:
2968                  str = faPtr->family;                  str = faPtr->family;
2969                  valuePtr = Tcl_NewStringObj(str, ((str == NULL) ? 0 : -1));                  valuePtr = Tcl_NewStringObj(str, ((str == NULL) ? 0 : -1));
2970                  break;                  break;
2971    
2972              case FONT_SIZE:              case FONT_SIZE:
2973                  valuePtr = Tcl_NewIntObj(faPtr->size);                  valuePtr = Tcl_NewIntObj(faPtr->size);
2974                  break;                  break;
2975    
2976              case FONT_WEIGHT:              case FONT_WEIGHT:
2977                  str = TkFindStateString(weightMap, faPtr->weight);                  str = TkFindStateString(weightMap, faPtr->weight);
2978                  valuePtr = Tcl_NewStringObj(str, -1);                  valuePtr = Tcl_NewStringObj(str, -1);
2979                  break;                  break;
2980                    
2981              case FONT_SLANT:              case FONT_SLANT:
2982                  str = TkFindStateString(slantMap, faPtr->slant);                  str = TkFindStateString(slantMap, faPtr->slant);
2983                  valuePtr = Tcl_NewStringObj(str, -1);                  valuePtr = Tcl_NewStringObj(str, -1);
2984                  break;                  break;
2985    
2986              case FONT_UNDERLINE:              case FONT_UNDERLINE:
2987                  valuePtr = Tcl_NewBooleanObj(faPtr->underline);                  valuePtr = Tcl_NewBooleanObj(faPtr->underline);
2988                  break;                  break;
2989    
2990              case FONT_OVERSTRIKE:              case FONT_OVERSTRIKE:
2991                  valuePtr = Tcl_NewBooleanObj(faPtr->overstrike);                  valuePtr = Tcl_NewBooleanObj(faPtr->overstrike);
2992                  break;                  break;
2993          }          }
2994          if (objPtr != NULL) {          if (objPtr != NULL) {
2995              Tcl_SetObjResult(interp, valuePtr);              Tcl_SetObjResult(interp, valuePtr);
2996              return TCL_OK;              return TCL_OK;
2997          }          }
2998          optionPtr = Tcl_NewStringObj(fontOpt[i], -1);          optionPtr = Tcl_NewStringObj(fontOpt[i], -1);
2999          Tcl_ListObjAppendElement(NULL, resultPtr, optionPtr);          Tcl_ListObjAppendElement(NULL, resultPtr, optionPtr);
3000          Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr);          Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr);
3001      }      }
3002      return TCL_OK;      return TCL_OK;
3003  }  }
3004    
3005  /*  /*
3006   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3007   *   *
3008   * ParseFontNameObj --   * ParseFontNameObj --
3009   *   *
3010   *      Converts a object into a set of font attributes that can be used   *      Converts a object into a set of font attributes that can be used
3011   *      to construct a font.   *      to construct a font.
3012   *   *
3013   *      The string rep of the object can be one of the following forms:   *      The string rep of the object can be one of the following forms:
3014   *              XLFD (see X documentation)   *              XLFD (see X documentation)
3015   *              "family [size] [style1 [style2 ...]"   *              "family [size] [style1 [style2 ...]"
3016   *              "-option value [-option value ...]"   *              "-option value [-option value ...]"
3017   *   *
3018   * Results:   * Results:
3019   *      The return value is TCL_ERROR if the object was syntactically   *      The return value is TCL_ERROR if the object was syntactically
3020   *      invalid.  In that case an error message is left in interp's   *      invalid.  In that case an error message is left in interp's
3021   *      result object.  Otherwise, fills the font attribute buffer with   *      result object.  Otherwise, fills the font attribute buffer with
3022   *      the values parsed from the string and returns TCL_OK;   *      the values parsed from the string and returns TCL_OK;
3023   *   *
3024   * Side effects:   * Side effects:
3025   *      None.   *      None.
3026   *   *
3027   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3028   */   */
3029    
3030  static int  static int
3031  ParseFontNameObj(interp, tkwin, objPtr, faPtr)  ParseFontNameObj(interp, tkwin, objPtr, faPtr)
3032      Tcl_Interp *interp;         /* Interp for error return.  Must not be      Tcl_Interp *interp;         /* Interp for error return.  Must not be
3033                                   * NULL. */                                   * NULL. */
3034      Tk_Window tkwin;            /* For display on which font is used. */      Tk_Window tkwin;            /* For display on which font is used. */
3035      Tcl_Obj *objPtr;            /* Parseable font description object. */      Tcl_Obj *objPtr;            /* Parseable font description object. */
3036      TkFontAttributes *faPtr;    /* Filled with attributes parsed from font      TkFontAttributes *faPtr;    /* Filled with attributes parsed from font
3037                                   * name.  Any attributes that were not                                   * name.  Any attributes that were not
3038                                   * specified in font name are filled with                                   * specified in font name are filled with
3039                                   * default values. */                                   * default values. */
3040  {  {
3041      char *dash;      char *dash;
3042      int objc, result, i, n;      int objc, result, i, n;
3043      Tcl_Obj **objv;      Tcl_Obj **objv;
3044      char *string;      char *string;
3045            
3046      TkInitFontAttributes(faPtr);      TkInitFontAttributes(faPtr);
3047    
3048      string = Tcl_GetString(objPtr);      string = Tcl_GetString(objPtr);
3049      if (*string == '-') {      if (*string == '-') {
3050          /*          /*
3051           * This may be an XLFD or an "-option value" string.           * This may be an XLFD or an "-option value" string.
3052           *           *
3053           * If the string begins with "-*" or a "-foundry-family-*" pattern,           * If the string begins with "-*" or a "-foundry-family-*" pattern,
3054           * then consider it an XLFD.             * then consider it an XLFD.  
3055           */           */
3056    
3057          if (string[1] == '*') {          if (string[1] == '*') {
3058              goto xlfd;              goto xlfd;
3059          }          }
3060          dash = strchr(string + 1, '-');          dash = strchr(string + 1, '-');
3061          if ((dash != NULL)          if ((dash != NULL)
3062                  && (!isspace(UCHAR(dash[-1])))) { /* INTL: ISO space */                  && (!isspace(UCHAR(dash[-1])))) { /* INTL: ISO space */
3063              goto xlfd;              goto xlfd;
3064          }          }
3065    
3066          if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {          if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
3067              return TCL_ERROR;              return TCL_ERROR;
3068          }          }
3069    
3070          return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr);          return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr);
3071      }      }
3072            
3073      if (*string == '*') {      if (*string == '*') {
3074          /*          /*
3075           * This is appears to be an XLFD.  Under Unix, all valid XLFDs were           * This is appears to be an XLFD.  Under Unix, all valid XLFDs were
3076           * already handled by TkpGetNativeFont.  If we are here, either we           * already handled by TkpGetNativeFont.  If we are here, either we
3077           * have something that initially looks like an XLFD but isn't or we           * have something that initially looks like an XLFD but isn't or we
3078           * have encountered an XLFD on Windows or Mac.           * have encountered an XLFD on Windows or Mac.
3079           */           */
3080    
3081          xlfd:          xlfd:
3082          result = TkFontParseXLFD(string, faPtr, NULL);          result = TkFontParseXLFD(string, faPtr, NULL);
3083          if (result == TCL_OK) {          if (result == TCL_OK) {
3084              return TCL_OK;              return TCL_OK;
3085          }          }
3086      }      }
3087    
3088      /*      /*
3089       * Wasn't an XLFD or "-option value" string.  Try it as a       * Wasn't an XLFD or "-option value" string.  Try it as a
3090       * "font size style" list.       * "font size style" list.
3091       */       */
3092    
3093      if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK)      if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK)
3094              || (objc < 1)) {              || (objc < 1)) {
3095          Tcl_AppendResult(interp, "font \"", string, "\" doesn't exist",          Tcl_AppendResult(interp, "font \"", string, "\" doesn't exist",
3096                  (char *) NULL);                  (char *) NULL);
3097          return TCL_ERROR;          return TCL_ERROR;
3098      }      }
3099    
3100      faPtr->family = Tk_GetUid(Tcl_GetString(objv[0]));      faPtr->family = Tk_GetUid(Tcl_GetString(objv[0]));
3101      if (objc > 1) {      if (objc > 1) {
3102          if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) {          if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) {
3103              return TCL_ERROR;              return TCL_ERROR;
3104          }          }
3105          faPtr->size = n;          faPtr->size = n;
3106      }      }
3107    
3108      i = 2;      i = 2;
3109      if (objc == 3) {      if (objc == 3) {
3110          if (Tcl_ListObjGetElements(interp, objv[2], &objc, &objv) != TCL_OK) {          if (Tcl_ListObjGetElements(interp, objv[2], &objc, &objv) != TCL_OK) {
3111              return TCL_ERROR;              return TCL_ERROR;
3112          }          }
3113          i = 0;          i = 0;
3114      }      }
3115      for ( ; i < objc; i++) {      for ( ; i < objc; i++) {
3116          n = TkFindStateNumObj(NULL, NULL, weightMap, objv[i]);          n = TkFindStateNumObj(NULL, NULL, weightMap, objv[i]);
3117          if (n != TK_FW_UNKNOWN) {          if (n != TK_FW_UNKNOWN) {
3118              faPtr->weight = n;              faPtr->weight = n;
3119              continue;              continue;
3120          }          }
3121          n = TkFindStateNumObj(NULL, NULL, slantMap, objv[i]);          n = TkFindStateNumObj(NULL, NULL, slantMap, objv[i]);
3122          if (n != TK_FS_UNKNOWN) {          if (n != TK_FS_UNKNOWN) {
3123              faPtr->slant = n;              faPtr->slant = n;
3124              continue;              continue;
3125          }          }
3126          n = TkFindStateNumObj(NULL, NULL, underlineMap, objv[i]);          n = TkFindStateNumObj(NULL, NULL, underlineMap, objv[i]);
3127          if (n != 0) {          if (n != 0) {
3128              faPtr->underline = n;              faPtr->underline = n;
3129              continue;              continue;
3130          }          }
3131          n = TkFindStateNumObj(NULL, NULL, overstrikeMap, objv[i]);          n = TkFindStateNumObj(NULL, NULL, overstrikeMap, objv[i]);
3132          if (n != 0) {          if (n != 0) {
3133              faPtr->overstrike = n;              faPtr->overstrike = n;
3134              continue;              continue;
3135          }          }
3136    
3137          /*          /*
3138           * Unknown style.           * Unknown style.
3139           */           */
3140    
3141          Tcl_AppendResult(interp, "unknown font style \"",          Tcl_AppendResult(interp, "unknown font style \"",
3142                  Tcl_GetString(objv[i]), "\"", (char *) NULL);                  Tcl_GetString(objv[i]), "\"", (char *) NULL);
3143          return TCL_ERROR;          return TCL_ERROR;
3144      }      }
3145      return TCL_OK;      return TCL_OK;
3146  }  }
3147    
3148  /*  /*
3149   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3150   *   *
3151   * NewChunk --   * NewChunk --
3152   *   *
3153   *      Helper function for Tk_ComputeTextLayout().  Encapsulates a   *      Helper function for Tk_ComputeTextLayout().  Encapsulates a
3154   *      measured set of characters in a chunk that can be quickly   *      measured set of characters in a chunk that can be quickly
3155   *      drawn.   *      drawn.
3156   *   *
3157   * Results:   * Results:
3158   *      A pointer to the new chunk in the text layout.   *      A pointer to the new chunk in the text layout.
3159   *   *
3160   * Side effects:   * Side effects:
3161   *      The text layout is reallocated to hold more chunks as necessary.   *      The text layout is reallocated to hold more chunks as necessary.
3162   *   *
3163   *      Currently, Tk_ComputeTextLayout() stores contiguous ranges of   *      Currently, Tk_ComputeTextLayout() stores contiguous ranges of
3164   *      "normal" characters in a chunk, along with individual tab   *      "normal" characters in a chunk, along with individual tab
3165   *      and newline chars in their own chunks.  All characters in the   *      and newline chars in their own chunks.  All characters in the
3166   *      text layout are accounted for.   *      text layout are accounted for.
3167   *   *
3168   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3169   */   */
3170  static LayoutChunk *  static LayoutChunk *
3171  NewChunk(layoutPtrPtr, maxPtr, start, numBytes, curX, newX, y)  NewChunk(layoutPtrPtr, maxPtr, start, numBytes, curX, newX, y)
3172      TextLayout **layoutPtrPtr;      TextLayout **layoutPtrPtr;
3173      int *maxPtr;      int *maxPtr;
3174      CONST char *start;      CONST char *start;
3175      int numBytes;      int numBytes;
3176      int curX;      int curX;
3177      int newX;      int newX;
3178      int y;      int y;
3179  {  {
3180      TextLayout *layoutPtr;      TextLayout *layoutPtr;
3181      LayoutChunk *chunkPtr;      LayoutChunk *chunkPtr;
3182      int maxChunks, numChars;      int maxChunks, numChars;
3183      size_t s;      size_t s;
3184            
3185      layoutPtr = *layoutPtrPtr;      layoutPtr = *layoutPtrPtr;
3186      maxChunks = *maxPtr;      maxChunks = *maxPtr;
3187      if (layoutPtr->numChunks == maxChunks) {      if (layoutPtr->numChunks == maxChunks) {
3188          maxChunks *= 2;          maxChunks *= 2;
3189          s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk));          s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk));
3190          layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s);          layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s);
3191    
3192          *layoutPtrPtr = layoutPtr;          *layoutPtrPtr = layoutPtr;
3193          *maxPtr = maxChunks;          *maxPtr = maxChunks;
3194      }      }
3195      numChars = Tcl_NumUtfChars(start, numBytes);      numChars = Tcl_NumUtfChars(start, numBytes);
3196      chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks];      chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks];
3197      chunkPtr->start             = start;      chunkPtr->start             = start;
3198      chunkPtr->numBytes          = numBytes;      chunkPtr->numBytes          = numBytes;
3199      chunkPtr->numChars          = numChars;      chunkPtr->numChars          = numChars;
3200      chunkPtr->numDisplayChars   = numChars;      chunkPtr->numDisplayChars   = numChars;
3201      chunkPtr->x                 = curX;      chunkPtr->x                 = curX;
3202      chunkPtr->y                 = y;      chunkPtr->y                 = y;
3203      chunkPtr->totalWidth        = newX - curX;      chunkPtr->totalWidth        = newX - curX;
3204      chunkPtr->displayWidth      = newX - curX;      chunkPtr->displayWidth      = newX - curX;
3205      layoutPtr->numChunks++;      layoutPtr->numChunks++;
3206    
3207      return chunkPtr;      return chunkPtr;
3208  }  }
3209    
3210  /*  /*
3211   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3212   *   *
3213   * TkFontParseXLFD --   * TkFontParseXLFD --
3214   *   *
3215   *      Break up a fully specified XLFD into a set of font attributes.   *      Break up a fully specified XLFD into a set of font attributes.
3216   *   *
3217   * Results:   * Results:
3218   *      Return value is TCL_ERROR if string was not a fully specified XLFD.   *      Return value is TCL_ERROR if string was not a fully specified XLFD.
3219   *      Otherwise, fills font attribute buffer with the values parsed   *      Otherwise, fills font attribute buffer with the values parsed
3220   *      from the XLFD and returns TCL_OK.     *      from the XLFD and returns TCL_OK.  
3221   *   *
3222   * Side effects:   * Side effects:
3223   *      None.   *      None.
3224   *   *
3225   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3226   */   */
3227    
3228  int  int
3229  TkFontParseXLFD(string, faPtr, xaPtr)  TkFontParseXLFD(string, faPtr, xaPtr)
3230      CONST char *string;         /* Parseable font description string. */      CONST char *string;         /* Parseable font description string. */
3231      TkFontAttributes *faPtr;    /* Filled with attributes parsed from font      TkFontAttributes *faPtr;    /* Filled with attributes parsed from font
3232                                   * name.  Any attributes that were not                                   * name.  Any attributes that were not
3233                                   * specified in font name are filled with                                   * specified in font name are filled with
3234                                   * default values. */                                   * default values. */
3235      TkXLFDAttributes *xaPtr;    /* Filled with X-specific attributes parsed      TkXLFDAttributes *xaPtr;    /* Filled with X-specific attributes parsed
3236                                   * from font name.  Any attributes that were                                   * from font name.  Any attributes that were
3237                                   * not specified in font name are filled with                                   * not specified in font name are filled with
3238                                   * default values.  May be NULL if such                                   * default values.  May be NULL if such
3239                                   * information is not desired. */                                   * information is not desired. */
3240  {  {
3241      char *src;      char *src;
3242      CONST char *str;      CONST char *str;
3243      int i, j;      int i, j;
3244      char *field[XLFD_NUMFIELDS + 2];      char *field[XLFD_NUMFIELDS + 2];
3245      Tcl_DString ds;      Tcl_DString ds;
3246      TkXLFDAttributes xa;      TkXLFDAttributes xa;
3247            
3248      if (xaPtr == NULL) {      if (xaPtr == NULL) {
3249          xaPtr = &xa;          xaPtr = &xa;
3250      }      }
3251      TkInitFontAttributes(faPtr);      TkInitFontAttributes(faPtr);
3252      TkInitXLFDAttributes(xaPtr);      TkInitXLFDAttributes(xaPtr);
3253    
3254      memset(field, '\0', sizeof(field));      memset(field, '\0', sizeof(field));
3255    
3256      str = string;      str = string;
3257      if (*str == '-') {      if (*str == '-') {
3258          str++;          str++;
3259      }      }
3260    
3261      Tcl_DStringInit(&ds);      Tcl_DStringInit(&ds);
3262      Tcl_DStringAppend(&ds, (char *) str, -1);      Tcl_DStringAppend(&ds, (char *) str, -1);
3263      src = Tcl_DStringValue(&ds);      src = Tcl_DStringValue(&ds);
3264    
3265      field[0] = src;      field[0] = src;
3266      for (i = 0; *src != '\0'; src++) {      for (i = 0; *src != '\0'; src++) {
3267          if (!(*src & 0x80)          if (!(*src & 0x80)
3268                  && Tcl_UniCharIsUpper(UCHAR(*src))) {                  && Tcl_UniCharIsUpper(UCHAR(*src))) {
3269              *src = (char) Tcl_UniCharToLower(UCHAR(*src));              *src = (char) Tcl_UniCharToLower(UCHAR(*src));
3270          }          }
3271          if (*src == '-') {          if (*src == '-') {
3272              i++;              i++;
3273              if (i == XLFD_NUMFIELDS) {              if (i == XLFD_NUMFIELDS) {
3274                  continue;                  continue;
3275              }              }
3276              *src = '\0';              *src = '\0';
3277              field[i] = src + 1;              field[i] = src + 1;
3278              if (i > XLFD_NUMFIELDS) {              if (i > XLFD_NUMFIELDS) {
3279                  break;                  break;
3280              }              }
3281          }          }
3282      }      }
3283    
3284      /*      /*
3285       * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common,       * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common,
3286       * but it is (strictly) malformed, because the first * is eliding both       * but it is (strictly) malformed, because the first * is eliding both
3287       * the Setwidth and the Addstyle fields.  If the Addstyle field is a       * the Setwidth and the Addstyle fields.  If the Addstyle field is a
3288       * number, then assume the above incorrect form was used and shift all       * number, then assume the above incorrect form was used and shift all
3289       * the rest of the fields right by one, so the number gets interpreted       * the rest of the fields right by one, so the number gets interpreted
3290       * as a pixelsize.  This fix is so that we don't get a million reports       * as a pixelsize.  This fix is so that we don't get a million reports
3291       * that "it works under X (as a native font name), but gives a syntax       * that "it works under X (as a native font name), but gives a syntax
3292       * error under Windows (as a parsed set of attributes)".       * error under Windows (as a parsed set of attributes)".
3293       */       */
3294    
3295      if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {      if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {
3296          if (atoi(field[XLFD_ADD_STYLE]) != 0) {          if (atoi(field[XLFD_ADD_STYLE]) != 0) {
3297              for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {              for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {
3298                  field[j + 1] = field[j];                  field[j + 1] = field[j];
3299              }              }
3300              field[XLFD_ADD_STYLE] = NULL;              field[XLFD_ADD_STYLE] = NULL;
3301              i++;              i++;
3302          }          }
3303      }      }
3304    
3305      /*      /*
3306       * Bail if we don't have enough of the fields (up to pointsize).       * Bail if we don't have enough of the fields (up to pointsize).
3307       */       */
3308    
3309      if (i < XLFD_FAMILY) {      if (i < XLFD_FAMILY) {
3310          Tcl_DStringFree(&ds);          Tcl_DStringFree(&ds);
3311          return TCL_ERROR;          return TCL_ERROR;
3312      }      }
3313    
3314      if (FieldSpecified(field[XLFD_FOUNDRY])) {      if (FieldSpecified(field[XLFD_FOUNDRY])) {
3315          xaPtr->foundry = Tk_GetUid(field[XLFD_FOUNDRY]);          xaPtr->foundry = Tk_GetUid(field[XLFD_FOUNDRY]);
3316      }      }
3317    
3318      if (FieldSpecified(field[XLFD_FAMILY])) {      if (FieldSpecified(field[XLFD_FAMILY])) {
3319          faPtr->family = Tk_GetUid(field[XLFD_FAMILY]);          faPtr->family = Tk_GetUid(field[XLFD_FAMILY]);
3320      }      }
3321      if (FieldSpecified(field[XLFD_WEIGHT])) {      if (FieldSpecified(field[XLFD_WEIGHT])) {
3322          faPtr->weight = TkFindStateNum(NULL, NULL, xlfdWeightMap,          faPtr->weight = TkFindStateNum(NULL, NULL, xlfdWeightMap,
3323                  field[XLFD_WEIGHT]);                  field[XLFD_WEIGHT]);
3324      }      }
3325      if (FieldSpecified(field[XLFD_SLANT])) {      if (FieldSpecified(field[XLFD_SLANT])) {
3326          xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap,          xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap,
3327                  field[XLFD_SLANT]);                  field[XLFD_SLANT]);
3328          if (xaPtr->slant == TK_FS_ROMAN) {          if (xaPtr->slant == TK_FS_ROMAN) {
3329              faPtr->slant = TK_FS_ROMAN;              faPtr->slant = TK_FS_ROMAN;
3330          } else {          } else {
3331              faPtr->slant = TK_FS_ITALIC;              faPtr->slant = TK_FS_ITALIC;
3332          }          }
3333      }      }
3334      if (FieldSpecified(field[XLFD_SETWIDTH])) {      if (FieldSpecified(field[XLFD_SETWIDTH])) {
3335          xaPtr->setwidth = TkFindStateNum(NULL, NULL, xlfdSetwidthMap,          xaPtr->setwidth = TkFindStateNum(NULL, NULL, xlfdSetwidthMap,
3336                  field[XLFD_SETWIDTH]);                  field[XLFD_SETWIDTH]);
3337      }      }
3338    
3339      /* XLFD_ADD_STYLE ignored. */      /* XLFD_ADD_STYLE ignored. */
3340    
3341      /*      /*
3342       * Pointsize in tenths of a point, but treat it as tenths of a pixel       * Pointsize in tenths of a point, but treat it as tenths of a pixel
3343       * for historical compatibility.       * for historical compatibility.
3344       */       */
3345    
3346      faPtr->size = 12;      faPtr->size = 12;
3347    
3348      if (FieldSpecified(field[XLFD_POINT_SIZE])) {      if (FieldSpecified(field[XLFD_POINT_SIZE])) {
3349          if (field[XLFD_POINT_SIZE][0] == '[') {          if (field[XLFD_POINT_SIZE][0] == '[') {
3350              /*              /*
3351               * Some X fonts have the point size specified as follows:               * Some X fonts have the point size specified as follows:
3352               *               *
3353               *      [ N1 N2 N3 N4 ]               *      [ N1 N2 N3 N4 ]
3354               *               *
3355               * where N1 is the point size (in points, not decipoints!), and               * where N1 is the point size (in points, not decipoints!), and
3356               * N2, N3, and N4 are some additional numbers that I don't know               * N2, N3, and N4 are some additional numbers that I don't know
3357               * the purpose of, so I ignore them.               * the purpose of, so I ignore them.
3358               */               */
3359    
3360              faPtr->size = atoi(field[XLFD_POINT_SIZE] + 1);              faPtr->size = atoi(field[XLFD_POINT_SIZE] + 1);
3361          } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE],          } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE],
3362                  &faPtr->size) == TCL_OK) {                  &faPtr->size) == TCL_OK) {
3363              faPtr->size /= 10;              faPtr->size /= 10;
3364          } else {          } else {
3365              return TCL_ERROR;              return TCL_ERROR;
3366          }          }
3367      }      }
3368    
3369      /*      /*
3370       * Pixel height of font.  If specified, overrides pointsize.       * Pixel height of font.  If specified, overrides pointsize.
3371       */       */
3372    
3373      if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {      if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
3374          if (field[XLFD_PIXEL_SIZE][0] == '[') {          if (field[XLFD_PIXEL_SIZE][0] == '[') {
3375              /*              /*
3376               * Some X fonts have the pixel size specified as follows:               * Some X fonts have the pixel size specified as follows:
3377               *               *
3378               *      [ N1 N2 N3 N4 ]               *      [ N1 N2 N3 N4 ]
3379               *               *
3380               * where N1 is the pixel size, and where N2, N3, and N4               * where N1 is the pixel size, and where N2, N3, and N4
3381               * are some additional numbers that I don't know               * are some additional numbers that I don't know
3382               * the purpose of, so I ignore them.               * the purpose of, so I ignore them.
3383               */               */
3384    
3385              faPtr->size = atoi(field[XLFD_PIXEL_SIZE] + 1);              faPtr->size = atoi(field[XLFD_PIXEL_SIZE] + 1);
3386          } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE],          } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE],
3387                  &faPtr->size) != TCL_OK) {                  &faPtr->size) != TCL_OK) {
3388              return TCL_ERROR;              return TCL_ERROR;
3389          }          }
3390      }      }
3391    
3392      faPtr->size = -faPtr->size;      faPtr->size = -faPtr->size;
3393    
3394      /* XLFD_RESOLUTION_X ignored. */      /* XLFD_RESOLUTION_X ignored. */
3395    
3396      /* XLFD_RESOLUTION_Y ignored. */      /* XLFD_RESOLUTION_Y ignored. */
3397    
3398      /* XLFD_SPACING ignored. */      /* XLFD_SPACING ignored. */
3399    
3400      /* XLFD_AVERAGE_WIDTH ignored. */      /* XLFD_AVERAGE_WIDTH ignored. */
3401    
3402      if (FieldSpecified(field[XLFD_CHARSET])) {      if (FieldSpecified(field[XLFD_CHARSET])) {
3403          xaPtr->charset = Tk_GetUid(field[XLFD_CHARSET]);          xaPtr->charset = Tk_GetUid(field[XLFD_CHARSET]);
3404      } else {      } else {
3405          xaPtr->charset = Tk_GetUid("iso8859-1");          xaPtr->charset = Tk_GetUid("iso8859-1");
3406      }      }
3407      Tcl_DStringFree(&ds);      Tcl_DStringFree(&ds);
3408      return TCL_OK;      return TCL_OK;
3409  }  }
3410    
3411  /*  /*
3412   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3413   *   *
3414   * FieldSpecified --   * FieldSpecified --
3415   *   *
3416   *      Helper function for TkParseXLFD().  Determines if a field in the   *      Helper function for TkParseXLFD().  Determines if a field in the
3417   *      XLFD was set to a non-null, non-don't-care value.   *      XLFD was set to a non-null, non-don't-care value.
3418   *   *
3419   * Results:   * Results:
3420   *      The return value is 0 if the field in the XLFD was not set and   *      The return value is 0 if the field in the XLFD was not set and
3421   *      should be ignored, non-zero otherwise.   *      should be ignored, non-zero otherwise.
3422   *   *
3423   * Side effects:   * Side effects:
3424   *      None.   *      None.
3425   *   *
3426   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3427   */   */
3428    
3429  static int  static int
3430  FieldSpecified(field)  FieldSpecified(field)
3431      CONST char *field;  /* The field of the XLFD to check.  Strictly      CONST char *field;  /* The field of the XLFD to check.  Strictly
3432                           * speaking, only when the string is "*" does it mean                           * speaking, only when the string is "*" does it mean
3433                           * don't-care.  However, an unspecified or question                           * don't-care.  However, an unspecified or question
3434                           * mark is also interpreted as don't-care. */                           * mark is also interpreted as don't-care. */
3435  {  {
3436      char ch;      char ch;
3437    
3438      if (field == NULL) {      if (field == NULL) {
3439          return 0;          return 0;
3440      }      }
3441      ch = field[0];      ch = field[0];
3442      return (ch != '*' && ch != '?');      return (ch != '*' && ch != '?');
3443  }  }
3444    
3445  /*  /*
3446   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3447   *   *
3448   * TkFontGetPixels --   * TkFontGetPixels --
3449   *   *
3450   *      Given a font size specification (as described in the TkFontAttributes   *      Given a font size specification (as described in the TkFontAttributes
3451   *      structure) return the number of pixels it represents.   *      structure) return the number of pixels it represents.
3452   *   *
3453   * Results:   * Results:
3454   *      As above.   *      As above.
3455   *   *
3456   * Side effects:   * Side effects:
3457   *      None.   *      None.
3458   *   *
3459   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3460   */   */
3461    
3462  int  int
3463  TkFontGetPixels(tkwin, size)  TkFontGetPixels(tkwin, size)
3464      Tk_Window tkwin;            /* For point->pixel conversion factor. */      Tk_Window tkwin;            /* For point->pixel conversion factor. */
3465      int size;                   /* Font size. */      int size;                   /* Font size. */
3466  {  {
3467      double d;      double d;
3468    
3469      if (size < 0) {      if (size < 0) {
3470          return -size;          return -size;
3471      }      }
3472    
3473      d = size * 25.4 / 72.0;      d = size * 25.4 / 72.0;
3474      d *= WidthOfScreen(Tk_Screen(tkwin));      d *= WidthOfScreen(Tk_Screen(tkwin));
3475      d /= WidthMMOfScreen(Tk_Screen(tkwin));      d /= WidthMMOfScreen(Tk_Screen(tkwin));
3476      return (int) (d + 0.5);      return (int) (d + 0.5);
3477  }  }
3478    
3479  /*  /*
3480   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3481   *   *
3482   * TkFontGetPoints --   * TkFontGetPoints --
3483   *   *
3484   *      Given a font size specification (as described in the TkFontAttributes   *      Given a font size specification (as described in the TkFontAttributes
3485   *      structure) return the number of points it represents.   *      structure) return the number of points it represents.
3486   *   *
3487   * Results:   * Results:
3488   *      As above.   *      As above.
3489   *   *
3490   * Side effects:   * Side effects:
3491   *      None.   *      None.
3492   *   *
3493   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
3494   */   */
3495    
3496  int  int
3497  TkFontGetPoints(tkwin, size)  TkFontGetPoints(tkwin, size)
3498      Tk_Window tkwin;            /* For pixel->point conversion factor. */      Tk_Window tkwin;            /* For pixel->point conversion factor. */
3499      int size;                   /* Font size. */      int size;                   /* Font size. */
3500  {  {
3501      double d;      double d;
3502    
3503      if (size >= 0) {      if (size >= 0) {
3504          return size;          return size;
3505      }      }
3506    
3507      d = -size * 72.0 / 25.4;      d = -size * 72.0 / 25.4;
3508      d *= WidthMMOfScreen(Tk_Screen(tkwin));      d *= WidthMMOfScreen(Tk_Screen(tkwin));
3509      d /= WidthOfScreen(Tk_Screen(tkwin));      d /= WidthOfScreen(Tk_Screen(tkwin));
3510      return (int) (d + 0.5);      return (int) (d + 0.5);
3511  }  }
3512    
3513  /*  /*
3514   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
3515   *   *
3516   * TkFontGetAliasList --   * TkFontGetAliasList --
3517   *   *
3518   *      Given a font name, find the list of all aliases for that font   *      Given a font name, find the list of all aliases for that font
3519   *      name.  One of the names in this list will probably be the name   *      name.  One of the names in this list will probably be the name
3520   *      that this platform expects when asking for the font.   *      that this platform expects when asking for the font.
3521   *   *
3522   * Results:   * Results:
3523   *      As above.  The return value is NULL if the font name has no   *      As above.  The return value is NULL if the font name has no
3524   *      aliases.   *      aliases.
3525   *   *
3526   * Side effects:   * Side effects:
3527   *      None.   *      None.
3528   *   *
3529   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
3530   */   */
3531                    
3532  char **  char **
3533  TkFontGetAliasList(faceName)  TkFontGetAliasList(faceName)
3534      CONST char *faceName;       /* Font name to test for aliases. */      CONST char *faceName;       /* Font name to test for aliases. */
3535  {    {  
3536      int i, j;      int i, j;
3537    
3538      for (i = 0; fontAliases[i] != NULL; i++) {      for (i = 0; fontAliases[i] != NULL; i++) {
3539          for (j = 0; fontAliases[i][j] != NULL; j++) {          for (j = 0; fontAliases[i][j] != NULL; j++) {
3540              if (strcasecmp(faceName, fontAliases[i][j]) == 0) {              if (strcasecmp(faceName, fontAliases[i][j]) == 0) {
3541                  return fontAliases[i];                  return fontAliases[i];
3542              }              }
3543          }          }
3544      }      }
3545      return NULL;      return NULL;
3546  }  }
3547    
3548  /*  /*
3549   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
3550   *   *
3551   * TkFontGetFallbacks --   * TkFontGetFallbacks --
3552   *   *
3553   *      Get the list of font fallbacks that the platform-specific code   *      Get the list of font fallbacks that the platform-specific code
3554   *      can use to try to find the closest matching font the name   *      can use to try to find the closest matching font the name
3555   *      requested.   *      requested.
3556   *   *
3557   * Results:   * Results:
3558   *      As above.   *      As above.
3559   *   *
3560   * Side effects:   * Side effects:
3561   *      None.   *      None.
3562   *   *
3563   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
3564   */   */
3565                    
3566  char ***  char ***
3567  TkFontGetFallbacks()  TkFontGetFallbacks()
3568  {  {
3569      return fontFallbacks;      return fontFallbacks;
3570  }  }
3571    
3572  /*  /*
3573   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
3574   *   *
3575   * TkFontGetGlobalClass --   * TkFontGetGlobalClass --
3576   *   *
3577   *      Get the list of fonts to try if the requested font name does not   *      Get the list of fonts to try if the requested font name does not
3578   *      exist and no fallbacks for that font name could be used either.   *      exist and no fallbacks for that font name could be used either.
3579   *      The names in this list are considered preferred over all the other   *      The names in this list are considered preferred over all the other
3580   *      font names in the system when looking for a last-ditch fallback.   *      font names in the system when looking for a last-ditch fallback.
3581   *   *
3582   * Results:   * Results:
3583   *      As above.   *      As above.
3584   *   *
3585   * Side effects:   * Side effects:
3586   *      None.   *      None.
3587   *   *
3588   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
3589   */   */
3590                    
3591  char **  char **
3592  TkFontGetGlobalClass()  TkFontGetGlobalClass()
3593  {  {
3594      return globalFontClass;      return globalFontClass;
3595  }  }
3596    
3597  /*  /*
3598   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
3599   *   *
3600   * TkFontGetSymbolClass --   * TkFontGetSymbolClass --
3601   *   *
3602   *      Get the list of fonts that are symbolic; used if the operating   *      Get the list of fonts that are symbolic; used if the operating
3603   *      system cannot apriori identify symbolic fonts on its own.   *      system cannot apriori identify symbolic fonts on its own.
3604   *   *
3605   * Results:   * Results:
3606   *      As above.   *      As above.
3607   *   *
3608   * Side effects:   * Side effects:
3609   *      None.   *      None.
3610   *   *
3611   *-------------------------------------------------------------------------   *-------------------------------------------------------------------------
3612   */   */
3613                    
3614  char **  char **
3615  TkFontGetSymbolClass()  TkFontGetSymbolClass()
3616  {  {
3617      return symbolClass;      return symbolClass;
3618  }  }
3619    
3620  /*  /*
3621   *----------------------------------------------------------------------   *----------------------------------------------------------------------
3622   *   *
3623   * TkDebugFont --   * TkDebugFont --
3624   *   *
3625   *      This procedure returns debugging information about a font.   *      This procedure returns debugging information about a font.
3626   *   *
3627   * Results:   * Results:
3628   *      The return value is a list with one sublist for each TkFont   *      The return value is a list with one sublist for each TkFont
3629   *      corresponding to "name".  Each sublist has two elements that   *      corresponding to "name".  Each sublist has two elements that
3630   *      contain the resourceRefCount and objRefCount fields from the   *      contain the resourceRefCount and objRefCount fields from the
3631   *      TkFont structure.   *      TkFont structure.
3632   *   *
3633   * Side effects:   * Side effects:
3634   *      None.   *      None.
3635   *   *
3636   *----------------------------------------------------------------------   *----------------------------------------------------------------------
3637   */   */
3638    
3639  Tcl_Obj *  Tcl_Obj *
3640  TkDebugFont(tkwin, name)  TkDebugFont(tkwin, name)
3641      Tk_Window tkwin;            /* The window in which the font will be      Tk_Window tkwin;            /* The window in which the font will be
3642                                   * used (not currently used). */                                   * used (not currently used). */
3643      char *name;                 /* Name of the desired color. */      char *name;                 /* Name of the desired color. */
3644  {  {
3645      TkFont *fontPtr;      TkFont *fontPtr;
3646      Tcl_HashEntry *hashPtr;      Tcl_HashEntry *hashPtr;
3647      Tcl_Obj *resultPtr, *objPtr;      Tcl_Obj *resultPtr, *objPtr;
3648    
3649      resultPtr = Tcl_NewObj();      resultPtr = Tcl_NewObj();
3650      hashPtr = Tcl_FindHashEntry(      hashPtr = Tcl_FindHashEntry(
3651              &((TkWindow *) tkwin)->mainPtr->fontInfoPtr->fontCache, name);              &((TkWindow *) tkwin)->mainPtr->fontInfoPtr->fontCache, name);
3652      if (hashPtr != NULL) {      if (hashPtr != NULL) {
3653          fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr);          fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr);
3654          if (fontPtr == NULL) {          if (fontPtr == NULL) {
3655              panic("TkDebugFont found empty hash table entry");              panic("TkDebugFont found empty hash table entry");
3656          }          }
3657          for ( ; (fontPtr != NULL); fontPtr = fontPtr->nextPtr) {          for ( ; (fontPtr != NULL); fontPtr = fontPtr->nextPtr) {
3658              objPtr = Tcl_NewObj();              objPtr = Tcl_NewObj();
3659              Tcl_ListObjAppendElement(NULL, objPtr,              Tcl_ListObjAppendElement(NULL, objPtr,
3660                      Tcl_NewIntObj(fontPtr->resourceRefCount));                      Tcl_NewIntObj(fontPtr->resourceRefCount));
3661              Tcl_ListObjAppendElement(NULL, objPtr,              Tcl_ListObjAppendElement(NULL, objPtr,
3662                      Tcl_NewIntObj(fontPtr->objRefCount));                      Tcl_NewIntObj(fontPtr->objRefCount));
3663              Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);              Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);
3664          }          }
3665      }      }
3666      return resultPtr;      return resultPtr;
3667  }  }
3668    
3669  /* End of tkfont.c */  /* End of tkfont.c */

Legend:
Removed from v.69  
changed lines
  Added in v.98

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25