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

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkfont.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25