home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tk42r2s.zip
/
tk4.2
/
os2
/
tkOS2Font.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-07-26
|
44KB
|
1,318 lines
/*
* tkOS2Font.c --
*
* This file contains the Xlib emulation routines relating to
* creating and manipulating fonts.
*
* Copyright (c) 1996-1998 Illya Vaes
* Copyright (c) 1995 Sun Microsystems, Inc.
* Copyright (c) 1994 Software Research Associates, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tkOS2Int.h"
/*
* Forward declarations for functions used in this file.
*/
static int NameToFont (_Xconst char *name, TkOS2Font *logfont);
static int XNameToFont (_Xconst char *name, TkOS2Font *logfont);
/*
* Code pages used in this file, 1004 is Windows compatible, 65400 must be
* used if the font contains special glyphs, ie. Symbol.
*/
#define CP_LATIN1 850L
#define CP_1004 1004L
#define CP_65400 65400L
#ifdef IGNOREPMRES
/*
* Shrink 120 to the value of overrideResolution to facilitate 'better'
* sizing for those displays which report a resolution of 120dpi but have
* actual resolution close to 96dpi (VGA upto ?800x600?).
* This is obviously dependent on both resolution and screen size,
* as higher resolutions usually use 120dpi fonts, regardless of any
* screen size.
*/
#define PIXTOPOINT(pixels) ( \
(aDevCaps[CAPS_VERTICAL_FONT_RES] == 120) \
? (((pixels) * 72) / overrideResolution) \
: (((pixels) * 72) / aDevCaps[CAPS_VERTICAL_FONT_RES]) \
)
#define POINTTOPIX(points) ( \
(aDevCaps[CAPS_VERTICAL_FONT_RES] == 120) \
? (((points) * overrideResolution) / 72) \
: (((points) * aDevCaps[CAPS_VERTICAL_FONT_RES]) / 72) \
)
#define PTOP(p) ( \
(aDevCaps[CAPS_VERTICAL_FONT_RES] == 120) \
? (((p) * overrideResolution) / 120 ) \
: (p) \
)
#define FIX_RES(res) (if (res==120) {res = overrideResolution})
#else
#define PIXTOPOINT(pixels) \
(((pixels) * 72) / aDevCaps[CAPS_VERTICAL_FONT_RES])
#define POINTTOPIX(points) \
(((points) * aDevCaps[CAPS_VERTICAL_FONT_RES]) / 72)
#define PTOP(p) (p)
#define FIX_RES(res)
#endif
/*
*----------------------------------------------------------------------
*
* NameToFont --
*
* Converts into a logical font description:
* - a three part font name of the form:
* "Family point_size style_list"
* Style_list contains a list of one or more attributes:
* normal, bold, italic, underline, strikeout
* Point size in decipoints.
*
* Results:
* Returns false if the font name was syntactically invalid,
* else true. Sets the fields of the passed in TkOS2Font.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
NameToFont(name, logfont)
_Xconst char *name;
TkOS2Font *logfont;
{
int argc, argc2;
char **argv, **argv2;
int nameLen, i, pointSize = 0;
if (Tcl_SplitList(NULL, (char *) name, &argc, &argv) != TCL_OK) {
return False;
}
if (argc != 3) {
ckfree((char *) argv);
return False;
}
/*
* Determine the font family name.
*/
nameLen = strlen(argv[0]);
if (nameLen > FACESIZE) {
nameLen = FACESIZE;
}
strncpy(logfont->fattrs.szFacename, argv[0], nameLen);
/*
* Check the character set.
*/
logfont->fattrs.usCodePage = 0;
if (stricmp(logfont->fattrs.szFacename, "Symbol") == 0) {
logfont->fattrs.usCodePage = CP_65400;
} else if (stricmp(logfont->fattrs.szFacename, "Symbol Set") == 0) {
logfont->fattrs.usCodePage = CP_65400;
} else if (stricmp(logfont->fattrs.szFacename, "WingDings") == 0) {
logfont->fattrs.usCodePage = CP_65400;
} else if (stricmp(logfont->fattrs.szFacename, "ZapfDingbats") == 0) {
logfont->fattrs.usCodePage = CP_65400;
} else if (stricmp(logfont->fattrs.szFacename, "StarBats") == 0) {
logfont->fattrs.usCodePage = CP_65400;
}
/*
* Determine the font size.
*/
if (Tcl_GetInt(NULL, argv[1], &pointSize) != TCL_OK) {
ckfree((char *) argv);
return False;
}
logfont->fattrs.lMaxBaselineExt = POINTTOPIX(pointSize);
logfont->deciPoints = pointSize;
/*
* Apply any style modifiers.
*/
if (Tcl_SplitList(NULL, (char *) argv[2], &argc2, &argv2) != TCL_OK) {
ckfree((char*) argv);
return False;
}
for (i = 0; i < argc2; i++) {
if (stricmp(argv2[i], "bold") == 0) {
logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
} else if (stricmp(argv2[i], "heavy") == 0) {
logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
} else if (stricmp(argv2[i], "semibold") == 0) {
logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
} else if (stricmp(argv2[i], "extrabold") == 0) {
logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
} else if (stricmp(argv2[i], "italic") == 0) {
logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
} else if (stricmp(argv2[i], "oblique") == 0) {
logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
} else if (stricmp(argv2[i], "underline") == 0) {
logfont->fattrs.fsSelection |= FATTR_SEL_UNDERSCORE;
} else if (stricmp(argv2[i], "strikeout") == 0) {
logfont->fattrs.fsSelection |= FATTR_SEL_STRIKEOUT;
} else {
/* ignore for now */
}
}
ckfree((char *) argv);
ckfree((char *) argv2);
return True;
}
/*
*----------------------------------------------------------------------
*
* XNameToFont --
*
* This function constructs a logical font description from an
* X font name. This code only handles font names with all 13
* parts, although a part can be '*'.
*
* Results:
* Returns false if the font name was syntactically invalid,
* else true. Sets the fields of the passed in TkOS2Font.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
XNameToFont(name, logfont)
_Xconst char *name;
TkOS2Font *logfont;
{
const char *head, *tail;
const char *field[13];
int flen[13];
int i, len, togo = 0;
/*
* Valid font name patterns must have a leading '-' or '*'.
*/
head = tail = name;
if (*tail == '-') {
head++; tail++;
} else if (*tail != '*') {
return FALSE;
}
/*
* Identify field boundaries. Stores a pointer to the beginning
* of each field in field[i], and the length of the field in flen[i].
* Fields are separated by dashes. Each '*' becomes a field by itself.
*/
i = 0;
while (*tail != '\0' && i < 12) {
if (*tail == '-') {
flen[i] = tail - head;
field[i] = head;
tail++;
head = tail;
i++;
} else if (*tail == '*') {
len = tail - head;
if (len > 0) {
flen[i] = tail - head;
field[i] = head;
} else {
flen[i] = 1;
field[i] = head;
tail++;
if (*tail == '-') {
tail++;
}
}
head = tail;
i++;
} else {
tail++;
}
}
/*
* We handle the last field as a special case, since it may contain
* an embedded hyphen.
*/
flen[i] = strlen(head);
field[i] = head;
/*
* Bail if we don't have at least a font and size.
*/
if (i < 8) {
return FALSE;
}
togo=i;
/*
* Now fill in the logical font description from the fields we have
* identified.
*/
/*
* Field 1: Foundry. Skip.
*/
if (--togo <= 0) return TRUE;
/*
* Field 2: Font Family.
*/
i = 1;
if (!(flen[i] == 0 ||
(flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
{
len = (flen[i] < FACESIZE) ? flen[i] : FACESIZE - 1;
strncpy(logfont->fattrs.szFacename, field[i], len);
/*
* Need to handle Symbol fonts specially.
*/
if (stricmp(logfont->fattrs.szFacename, "Symbol") == 0) {
logfont->fattrs.usCodePage = CP_65400;
} else if (stricmp(logfont->fattrs.szFacename, "Symbol Set") == 0) {
logfont->fattrs.usCodePage = CP_65400;
} else if (stricmp(logfont->fattrs.szFacename, "WingDings") == 0) {
logfont->fattrs.usCodePage = CP_65400;
} else if (stricmp(logfont->fattrs.szFacename, "ZapfDingbats") == 0) {
logfont->fattrs.usCodePage = CP_65400;
} else if (stricmp(logfont->fattrs.szFacename, "StarBats") == 0) {
logfont->fattrs.usCodePage = CP_65400;
}
}
if (--togo <= 0) return TRUE;
/*
* Field 3: Weight. Default is medium.
*/
i = 2;
if ((flen[i] > 0) && (strnicmp(field[i], "bold", flen[i]) == 0)) {
logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
} else {
logfont->fattrs.fsSelection &= ~FATTR_SEL_BOLD;
}
if (--togo <= 0) return TRUE;
/*
* Field 4: Slant. Default is Roman.
*/
i = 3;
if (!(flen[i] == 0 ||
(flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
{
if (strnicmp(field[i], "r", flen[i]) == 0) {
/* Roman. */
logfont->fattrs.fsSelection &= ~FATTR_SEL_ITALIC;
} else if (strnicmp(field[i], "i", flen[i]) == 0) {
/* Italic */
logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
} else if (strnicmp(field[i], "o", flen[i]) == 0) {
/* Oblique, set to 15 degree slant forward */
logfont->shear.x = 2588; /* 10000*cos(75) */
logfont->shear.y = 9659; /* 10000*sin(75) */
logfont->setShear = TRUE;
logfont->fattrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
} else if (strnicmp(field[i], "ri", flen[i]) == 0) {
/* Reverse Italic, set to 30 degree slant backward */
logfont->shear.x = -5000; /* 10000*cos(120) */
logfont->shear.y = 8660; /* 10000*sin(120) */
logfont->setShear = TRUE;
logfont->fattrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
} else if (strnicmp(field[i], "ro", flen[i]) == 0) {
/* Reverse Oblique, set to 15 degree slant backward */
logfont->shear.x = -2588; /* 10000*cos(105) */
logfont->shear.y = 9659; /* 10000*sin(105) */
logfont->setShear = TRUE;
logfont->fattrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
} else if (strnicmp(field[i], "ot", flen[i]) == 0) {
/* Other */
} else {
return FALSE;
}
}
if (--togo <= 0) return TRUE;
/*
* Field 5 & 6: Set Width & Blank. Skip.
*/
if (--togo <= 0) return TRUE;
/*
* Field 7: Pixels. Use this as the points if no points set.
*/
if (--togo <= 0) return TRUE;
i = 6;
if (!(flen[i] == 0 ||
(flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
{
logfont->fattrs.lMaxBaselineExt = atoi(field[i]);
/* Points is (pixels * 72) / FONT_RES ; Note: decipixels! */
logfont->deciPoints = PIXTOPOINT(logfont->fattrs.lMaxBaselineExt * 10);
}
if (--togo <= 0) return TRUE;
/*
* Field 8: Points in tenths of a point.
*/
i = 7;
if (!(flen[i] == 0 ||
(flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
{
logfont->deciPoints = atoi(field[i]);
logfont->fattrs.lMaxBaselineExt = POINTTOPIX(logfont->deciPoints) / 10;
}
if (--togo <= 0) return TRUE;
/*
* Field 9: Horizontal Resolution in DPI. Skip.
* Field 10: Vertical Resolution in DPI. Skip.
*/
if (--togo <= 0) return TRUE;
/*
* Field 11: Spacing.
* we can't request this via PM's TkOS2Font, so skip.
*/
if (--togo <= 0) return TRUE;
/*
* Field 12: Average Width.
* Width should be 0 for outline fonts.
*/
i = 11;
if (!(flen[i] == 0 ||
(flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
{
logfont->fattrs.lAveCharWidth = (atoi(field[i]) / 10);
}
if (--togo <= 0) return TRUE;
/*
* Field 13: Character Set. Skip.
*/
if (--togo <= 0) return TRUE;
return TRUE;
}
/*
*----------------------------------------------------------------------
*
* XLoadFont --
*
* Get the font handle for the specified font.
* Also handles:
* - a "Presentation Parameter"-style specification
* "pixelsize.fontname[.attr][.attr][.attr][.attr][.attr]"
* Each attr one of bold, italic, underline, strikeout, outline.
*
* Results:
* Returns the font handle.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Font
XLoadFont(display, name)
Display* display;
_Xconst char* name;
{
LONG lFontID= nextLogicalFont;
LONG match = 0;
PFONTMETRICS os2fonts;
LONG reqFonts, remFonts;
BOOL found = FALSE;
/* Use nominal size unless given Presentation Parameter style spec. */
/*
BOOL useIntended = TRUE;
*/
BOOL useIntended = FALSE;
LONG outline = -1;
LONG font = 0;
int i, error = 30000, best = -1;
if (lFontID > MAX_LID) {
/* We can't simultaneously use more than MAX_LID fonts */
return (Font) 0;
}
/* Set defaults in logfont */
logfonts[lFontID].fattrs.usRecordLength = (USHORT)sizeof(FATTRS);
logfonts[lFontID].fattrs.fsSelection = (USHORT)0;
logfonts[lFontID].fattrs.lMatch = 0L;
memset(logfonts[lFontID].fattrs.szFacename, '\0', FACESIZE);
logfonts[lFontID].fattrs.idRegistry = 0; /* Unknown */
logfonts[lFontID].fattrs.usCodePage = 0; /* Use present codepage */
logfonts[lFontID].fattrs.lMaxBaselineExt = 0L; /* 0 for vector fonts */
logfonts[lFontID].fattrs.lAveCharWidth = 0L; /* 0 for vector fonts */
logfonts[lFontID].fattrs.fsType = 0;
logfonts[lFontID].fattrs.fsFontUse = 0;
logfonts[lFontID].shear.x = 0;
logfonts[lFontID].shear.y = 1; /* Upright characters by default */
/* Not necessary to set shear by default */
logfonts[lFontID].setShear = FALSE;
logfonts[lFontID].outline = FALSE;
logfonts[lFontID].deciPoints = 120;
logfonts[lFontID].fattrs.lMaxBaselineExt = 12;
if (! (((name[0] == '-') || (name[0] == '*')) &&
XNameToFont(name, &logfonts[lFontID]))) {
if (!NameToFont(name, &logfonts[lFontID])) {
/* Our own (non-X) fonts, recognize Windows fontnames for
* compatibility of scripts.
*/
if ((stricmp(name, "system") == 0) || /* OS/2 and Windows font */
(stricmp(name, "device") == 0)) { /* Windows font */
strncpy(logfonts[lFontID].fattrs.szFacename, "System VIO", 10);
} else if ((strnicmp(name, "systemmonospaced", 16) == 0) ||
(strnicmp(name, "ansifixed", 9) == 0) || /* Windows font */
(strnicmp(name, "systemfixed", 11) == 0) || /* Windows font */
(strnicmp(name, "oemfixed", 8) == 0)) { /* Windows font */
strncpy(logfonts[lFontID].fattrs.szFacename, "System Monospaced", 17);
} else if ((strnicmp(name, "systemproportional", 18) == 0) ||
(strnicmp(name, "ansi", 4) == 0)) { /* Windows font */
strncpy(logfonts[lFontID].fattrs.szFacename, "System Proportional", 19);
} else {
/*
* The following code suggested by Ilya Zakharevich.
* Its use is to allow font selection "in OS/2-style", like
* "10.Courier".
* Ilya's way of supplying attributes of the font is against
* the documented "pointSize.Fontname[.attr ...]" though,
* because it gives attributes between the pointsize and the
* name of the font.
* I take the "official" stance and also supply the rest of the
* font Presentation Parameters: underline, strikeout, outline.
*/
int l, off = 0;
if (sscanf(name, "%d.%n", &l, &off) && off > 0) {
int fields;
/*
logfonts[lFontID].fattrs.lMaxBaselineExt = POINTTOPIX(l);
logfonts[lFontID].deciPoints = l * 10;
*/
logfonts[lFontID].fattrs.lMaxBaselineExt = l;
logfonts[lFontID].deciPoints = PIXTOPOINT(l * 10);
name += off;
useIntended = TRUE;
/* Get the fontname out */
fields = sscanf(name, "%[^.]%n",
(char *)&logfonts[lFontID].fattrs.szFacename,
&off);
if (fields==1 && strlen(name)==off) {
/* Fontname is last part */
l = strlen(name);
if (l > FACESIZE - 1) {
l = FACESIZE - 1;
}
strncpy(logfonts[lFontID].fattrs.szFacename, name, l);
} else {
/* There are attributes after the fontname */
name += off;
while (TRUE) {
if (strnicmp(name, ".bold", 5) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_BOLD;
name += 5;
} else if (strnicmp(name, ".italic", 7) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_ITALIC;
name += 7;
} else if (strnicmp(name, ".underline", 10) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_UNDERSCORE;
name += 10;
} else if (strnicmp(name, ".strikeout", 10) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_STRIKEOUT;
name += 10;
} else if (strnicmp(name, ".outline", 8) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_OUTLINE;
name += 8;
} else if (*name == '.') {
name++;
break;
} else {
break;
}
}
}
} else {
l = strlen(name);
if (l > FACESIZE - 1) {
l = FACESIZE - 1;
}
strncpy(logfonts[lFontID].fattrs.szFacename, name, l);
}
}
}
}
/* Name has now been filled in with a correct or sane value */
/* Determine number of fonts */
reqFonts = 0L;
remFonts = GpiQueryFonts(globalPS, QF_PUBLIC,
logfonts[lFontID].fattrs.szFacename, &reqFonts,
(LONG) sizeof(FONTMETRICS), NULL);
reqFonts = remFonts;
if (reqFonts) {
/* Allocate space for the fonts */
os2fonts = (PFONTMETRICS) ckalloc(remFonts * sizeof(FONTMETRICS));
if (os2fonts == NULL) {
return (Font) 0;
}
/* Get the fonts that apply */
remFonts = GpiQueryFonts(globalPS, QF_PUBLIC,
logfonts[lFontID].fattrs.szFacename, &reqFonts,
(LONG) sizeof(FONTMETRICS), os2fonts);
} else {
os2fonts = NULL;
}
/*
* Determine the one that has the right size, preferring a bitmap font over
* a scalable (outline) one if it exists.
*/
for (i=0; i<reqFonts && !found; i++) {
/*
* Note: scalable fonts appear to always return lEmHeight 16, so first
* check for outline, then "point size" to not match on size 16.
*/
if (os2fonts[i].fsDefn & FM_DEFN_OUTLINE) {
/* Remember we found an outline font */
outline = i;
} else {
/* Bitmap font, check size, type, resolution */
int cerror = 0, err1;
/*
* Note: FONTMETRICS.fsSelection can contain FM_SEL_ISO9241_TESTED,
* FATTRS.fsSelection cannot.
*/
/*
if (
((useIntended ? os2fonts[i].sNominalPointSize :
(os2fonts[i].lMaxBaselineExt * 10)) ==
logfonts[lFontID].fattrs.lMaxBaselineExt * 10)
*/
/* If we need a transformable font, we *need* an outline */
/*
&&
(!(logfonts[lFontID].fattrs.fsFontUse & FATTR_FONTUSE_TRANSFORMABLE))
&&
(os2fonts[i].sXDeviceRes == aDevCaps[CAPS_HORIZONTAL_FONT_RES])
&&
(os2fonts[i].sYDeviceRes == aDevCaps[CAPS_VERTICAL_FONT_RES])
) {
found = TRUE;
match = os2fonts[i].lMatch;
font = i;
*/
err1 = ( useIntended ? os2fonts[i].sNominalPointSize
: (os2fonts[i].lMaxBaselineExt * 10))
- logfonts[lFontID].fattrs.lMaxBaselineExt * 10;
if (err1 < 0) {
err1 = -err1;
}
cerror = err1;
if (logfonts[lFontID].fattrs.lAveCharWidth) {
err1 = logfonts[lFontID].fattrs.lAveCharWidth
- os2fonts[i].lAveCharWidth;
if (err1 < 0) {
err1 = -err1;
}
cerror += err1 * 3; /* 10/3 times cheaper */
}
if (os2fonts[i].sXDeviceRes != aDevCaps[CAPS_HORIZONTAL_FONT_RES] ||
os2fonts[i].sYDeviceRes != aDevCaps[CAPS_VERTICAL_FONT_RES]) {
cerror += 1;
}
if (cerror < error) {
error = cerror;
best = i;
}
if (cerror == 0) {
found = TRUE;
font = best;
match = os2fonts[best].lMatch;
}
}
}
/* If an exact bitmap for a different resolution found, take it */
if (!found && error <= 1) {
match = os2fonts[best].lMatch;
font = best;
found = TRUE;
}
/* If no bitmap but an outline found, take it */
if (!found && outline != -1) {
match = os2fonts[outline].lMatch;
font = outline;
found = TRUE;
logfonts[lFontID].outline = TRUE;
}
/* If no exact bitmap but an approximate found, take it */
if (!found && best != -1) {
match = os2fonts[best].lMatch;
font = best;
found = TRUE;
}
if (!found) {
/* Select default font by making facename empty */
memset(logfonts[lFontID].fattrs.szFacename, '\0', FACESIZE);
match= GpiCreateLogFont(globalPS, NULL, lFontID,
&(logfonts[lFontID].fattrs));
if (match == GPI_ERROR) {
if (os2fonts) {
ckfree((char *)os2fonts);
}
return (Font) 0;
} else if (match == FONT_DEFAULT) {
FONTMETRICS fm;
rc= GpiQueryFontMetrics(globalPS, sizeof(FONTMETRICS), &fm);
if (!rc) {
return (Font) 0;
}
logfonts[lFontID].fattrs.lMatch = 0;
strcpy(logfonts[lFontID].fattrs.szFacename, fm.szFacename);
logfonts[lFontID].fattrs.idRegistry = fm.idRegistry;
logfonts[lFontID].fattrs.usCodePage = fm.usCodePage;
logfonts[lFontID].fattrs.lMaxBaselineExt = fm.lMaxBaselineExt;
logfonts[lFontID].fattrs.lAveCharWidth = fm.lAveCharWidth;
logfonts[lFontID].fattrs.fsType = 0;
logfonts[lFontID].fattrs.fsFontUse = 0;
goto got_it;
}
}
/* Fill in the exact font metrics if we found a font */
if (!found) {
if (os2fonts) {
ckfree((char *)os2fonts);
}
return (Font) 0;
} else {
logfonts[lFontID].fattrs.idRegistry = os2fonts[font].idRegistry;
logfonts[lFontID].fattrs.lMatch = match;
strcpy(logfonts[lFontID].fattrs.szFacename, os2fonts[font].szFacename);
if (os2fonts[font].fsDefn & FM_DEFN_OUTLINE) {
logfonts[lFontID].fattrs.lMaxBaselineExt = 0;
logfonts[lFontID].fattrs.lAveCharWidth = 0;
logfonts[lFontID].fattrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
} else {
logfonts[lFontID].fattrs.lMaxBaselineExt =
os2fonts[font].lMaxBaselineExt;
logfonts[lFontID].fattrs.lAveCharWidth =
os2fonts[font].lAveCharWidth;
}
}
got_it:
match = GpiCreateLogFont(globalPS, NULL, lFontID,
&(logfonts[lFontID].fattrs));
if (match == GPI_ERROR) {
/* Select default font by making facename empty */
memset(logfonts[lFontID].fattrs.szFacename, '\0', FACESIZE);
match = GpiCreateLogFont(globalPS, NULL, lFontID,
&(logfonts[lFontID].fattrs));
}
/* Scale the font to the right size if outline font */
if (logfonts[lFontID].outline) {
rc = TkOS2ScaleFont(globalPS, logfonts[lFontID].deciPoints, 0);
}
if (match == GPI_ERROR) {
if (os2fonts) {
ckfree((char *)os2fonts);
}
return (Font) 0;
} else {
ckfree((char *)os2fonts);
nextLogicalFont++;
return (Font) lFontID;
}
}
/*
*----------------------------------------------------------------------
*
* XQueryFont --
*
* Retrieve information about the specified font.
*
* Results:
* Returns a newly allocated XFontStruct.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
XFontStruct *
XQueryFont(display, font_ID)
Display* display;
XID font_ID;
{
XFontStruct *fontPtr = (XFontStruct *) ckalloc(sizeof(XFontStruct));
LONG oldFont;
FONTMETRICS fm;
XCharStruct bounds;
BOOL rc;
POINTL noShear= {0, 1};
if (!fontPtr) {
return NULL;
}
fontPtr->fid = font_ID;
oldFont = GpiQueryCharSet(globalPS);
rc = GpiSetCharSet(globalPS, (LONG) fontPtr->fid);
/* Set slant if necessary */
if (logfonts[(LONG)fontPtr->fid].setShear) {
GpiSetCharShear(globalPS, &(logfonts[(LONG)fontPtr->fid].shear));
}
/*
* Determine the font metrics and store the values into the appropriate
* X data structures.
*/
/* If this is an outline font, set the char box */
if (logfonts[font_ID].outline) {
rc = TkOS2ScaleFont(globalPS, logfonts[font_ID].deciPoints, 0);
}
if (GpiQueryFontMetrics(globalPS, sizeof(FONTMETRICS), &fm)) {
/*
* Copy fontmetrics into own structure, so we remember scalable font
* modifications.
*/
memcpy((void *)&logfonts[font_ID].fm, (void *)&fm, sizeof(FONTMETRICS));
fontPtr->direction =
LOBYTE(fm.sInlineDir) < 90 || LOBYTE(fm.sInlineDir) > 270
? FontLeftToRight : FontRightToLeft;
fontPtr->min_byte1 = 0;
fontPtr->max_byte1 = 0;
fontPtr->min_char_or_byte2 = fm.sFirstChar;
/* sLastChar is *offset* from sFirstChar! */
fontPtr->max_char_or_byte2 = fm.sFirstChar + fm.sLastChar;
fontPtr->all_chars_exist = True;
fontPtr->default_char = fm.sDefaultChar;
fontPtr->n_properties = 0;
fontPtr->properties = NULL;
bounds.lbearing = 0;
bounds.rbearing = (short) fm.lMaxCharInc;
bounds.width = (short) fm.lMaxCharInc;
bounds.ascent = (short) fm.lMaxAscender;
bounds.descent = (short) fm.lMaxDescender;
bounds.attributes = 0;
fontPtr->ascent = fm.lMaxAscender;
fontPtr->descent = fm.lMaxDescender;
fontPtr->min_bounds = bounds;
fontPtr->max_bounds = bounds;
/*
* If the font is not fixed pitch, then we need to construct
* the per_char array.
*/
if ( !(fm.fsType & FM_TYPE_FIXED) ) {
int i;
char c;
/*
* sLastChar is offset from sFirstChar
* Only 256 code points (0 - 255) allowed in a code page.
*/
int nchars = MIN(((int)fm.sLastChar + 1), 255);
int minWidth = 30000;
POINTL endPoint[2];
PLONG widths;
fontPtr->per_char =
(XCharStruct *)ckalloc(sizeof(XCharStruct) * nchars);
/*
* GpiQueryCharStringPos seems to be more precise than
* GpiQueryWidthTable. In the widget demo, the first only exhibits
* some "dancing" when highlighting, while the latter gives a very
* noticeable space before the cursor.
* On the other hand, it is abysmal for raster fonts.
*/
if (logfonts[font_ID].outline) {
for (i = 0, c = fm.sFirstChar; i < nchars ; i++, c++ ) {
GpiQueryCharStringPos(globalPS, 0L, 1, &c, NULL, endPoint);
fontPtr->per_char[i].width = endPoint[1].x - endPoint[0].x;
if (minWidth > fontPtr->per_char[i].width) {
minWidth = fontPtr->per_char[i].width;
}
}
} else {
/* Bitmap -> use GpiQueryWidthTable */
widths = (PLONG) ckalloc(sizeof(LONG)*nchars);
if (widths != NULL) {
rc= GpiQueryWidthTable(globalPS, fm.sFirstChar, nchars,
widths);
if (rc == TRUE) {
for (i = 0; i < nchars ; i++) {
fontPtr->per_char[i] = bounds;
fontPtr->per_char[i].width = widths[i];
if (minWidth > fontPtr->per_char[i].width) {
minWidth = fontPtr->per_char[i].width;
}
}
} else {
ckfree((char *)fontPtr);
fontPtr = NULL;
}
} else {
ckfree((char *)fontPtr);
fontPtr = NULL;
goto restore;
}
}
fontPtr->min_bounds.width = minWidth;
} else {
fontPtr->per_char = NULL;
}
} else {
ckfree((char *)fontPtr);
fontPtr = NULL;
}
restore:
/* Restore font */
if (logfonts[(LONG)fontPtr->fid].setShear) {
GpiSetCharShear(globalPS, &noShear);
}
GpiSetCharSet(globalPS, oldFont);
return fontPtr;
}
/*
*----------------------------------------------------------------------
*
* XLoadQueryFont --
*
* Finds the closest available OS/2 font for the specified
* font name.
*
* Results:
* Allocates and returns an XFontStruct containing a description
* of the matching font.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
XFontStruct *
XLoadQueryFont(display, name)
Display* display;
_Xconst char* name;
{
Font font;
font = XLoadFont(display, name);
return XQueryFont(display, font);
}
/*
*----------------------------------------------------------------------
*
* XFreeFont --
*
* Releases resources associated with the specified font.
*
* Results:
* None.
*
* Side effects:
* Frees the memory referenced by font_struct.
*
*----------------------------------------------------------------------
*/
void
XFreeFont(display, font_struct)
Display* display;
XFontStruct* font_struct;
{
/* Only deleting the last ID can be done in this array-approach */
if (nextLogicalFont-1 == (LONG)font_struct->fid) {
GpiDeleteSetId(globalPS, (LONG)font_struct->fid);
nextLogicalFont--;
}
if (font_struct->per_char != NULL) {
ckfree((char *) font_struct->per_char);
}
ckfree((char *) font_struct);
}
/*
*----------------------------------------------------------------------
*
* XTextWidth --
*
* Compute the width of an 8-bit character string.
*
* Results:
* Returns the computed width of the specified string.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
XTextWidth(font_struct, string, count)
XFontStruct* font_struct;
_Xconst char* string;
int count;
{
/*
FONTMETRICS fm;
*/
LONG oldFont;
POINTL aSize[TXTBOX_COUNT];
POINTL noShear= {0, 1};
oldFont = GpiQueryCharSet(globalPS);
GpiSetCharSet(globalPS, (LONG) font_struct->fid);
/* Set slant if necessary */
if (logfonts[(LONG)font_struct->fid].setShear) {
GpiSetCharShear(globalPS, &(logfonts[(LONG)font_struct->fid].shear));
}
/* If this is an outline font, set the char box */
if (logfonts[(LONG)font_struct->fid].outline) {
rc = TkOS2ScaleFont(globalPS,
logfonts[(LONG)font_struct->fid].deciPoints, 0);
} else {
/*
* XTextWidth is only used by Tk as an average number, for '0'
* -> use lAveCharWidth
*/
return logfonts[(LONG)font_struct->fid].fattrs.lAveCharWidth;
}
GpiQueryTextBox(globalPS, count, (PCH)string, TXTBOX_COUNT, aSize);
/* OS/2 PM does not have ths overhang
* GpiQueryFontMetrics(globalPS, sizeof(FONTMETRICS), &fm);
* size.cx -= fm.fmOverhang;
*/
/* Restore font */
if (logfonts[(LONG)font_struct->fid].setShear) {
GpiSetCharShear(globalPS, &noShear);
}
GpiSetCharSet(globalPS, oldFont);
return aSize[TXTBOX_BOTTOMRIGHT].x - aSize[TXTBOX_BOTTOMLEFT].x;
}
/*
*----------------------------------------------------------------------
*
* XTextExtents --
*
* Compute the bounding box for a string.
*
* Results:
* Sets the direction_return, ascent_return, descent_return, and
* overall_return values as defined by Xlib.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
XTextExtents(font_struct, string, nchars, direction_return,
font_ascent_return, font_descent_return, overall_return)
XFontStruct* font_struct;
_Xconst char* string;
int nchars;
int* direction_return;
int* font_ascent_return;
int* font_descent_return;
XCharStruct* overall_return;
{
LONG oldFont;
POINTL aSize[TXTBOX_COUNT];
POINTL noShear= {0, 1};
*direction_return = font_struct->direction;
*font_ascent_return = font_struct->ascent;
*font_descent_return = font_struct->descent;
oldFont = GpiQueryCharSet(globalPS);
GpiSetCharSet(globalPS, (LONG) font_struct->fid);
/* Set slant if necessary */
if (logfonts[(LONG)font_struct->fid].setShear) {
GpiSetCharShear(globalPS, &(logfonts[(LONG)font_struct->fid].shear));
}
/* If this is an outline font, set the char box */
if (logfonts[(LONG)font_struct->fid].outline) {
rc = TkOS2ScaleFont(globalPS,
logfonts[(LONG)font_struct->fid].deciPoints, 0);
}
overall_return->ascent = (short)
logfonts[(LONG)font_struct->fid].fm.lMaxAscender;
overall_return->descent = (short)
logfonts[(LONG)font_struct->fid].fm.lMaxDescender;
GpiQueryTextBox(globalPS, nchars, (char *)string, TXTBOX_COUNT, aSize);
overall_return->width = (short) aSize[TXTBOX_BOTTOMRIGHT].x -
aSize[TXTBOX_BOTTOMLEFT].x;
overall_return->lbearing = 0;
overall_return->rbearing = (short) overall_return->width;
/* Restore font */
if (logfonts[(LONG)font_struct->fid].setShear) {
GpiSetCharShear(globalPS, &noShear);
}
GpiSetCharSet(globalPS, oldFont);
}
/*
*----------------------------------------------------------------------
*
* XGetFontProperty --
*
* Called to get font properties.
*
* Results:
* Return true for known properties, false otherwise
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Bool
XGetFontProperty(font_struct, atom, value_return)
XFontStruct* font_struct;
Atom atom;
unsigned long* value_return;
{
FONTMETRICS fm;
switch (atom) {
case XA_SUPERSCRIPT_X:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lSuperscriptXOffset;
return True;
break;
case XA_SUPERSCRIPT_Y:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lSuperscriptYOffset;
return True;
break;
case XA_SUBSCRIPT_X:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lSubscriptXOffset;
return True;
break;
case XA_SUBSCRIPT_Y:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lSubscriptYOffset;
return True;
break;
case XA_UNDERLINE_POSITION:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lUnderscorePosition;
return True;
break;
case XA_UNDERLINE_THICKNESS:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lUnderscoreSize;
return True;
break;
case XA_STRIKEOUT_ASCENT:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lStrikeoutPosition;
return True;
break;
case XA_STRIKEOUT_DESCENT:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lStrikeoutSize
- logfonts[(LONG)font_struct->fid].fm.lStrikeoutPosition;
return True;
break;
case XA_ITALIC_ANGLE: /* scaled by 64 */
/* Degrees in sCharSlope second byte, minutes first byte */
/* Endian-ness!!! */
*value_return = (unsigned long) 64 * 90 -
(logfonts[(LONG)font_struct->fid].fm.sCharSlope >> 2);
return True;
break;
case XA_X_HEIGHT:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lXHeight;
return True;
break;
case XA_QUAD_WIDTH:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lEmInc;
return True;
break;
case XA_CAP_HEIGHT:
/* Same as max height */
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.lMaxAscender;
return True;
break;
case XA_WEIGHT:
/* Scale of 0 to 1000 */
*value_return = (unsigned long)
100 * logfonts[(LONG)font_struct->fid].fm.usWeightClass;
return True;
break;
case XA_POINT_SIZE:
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.sNominalPointSize;
return True;
break;
case XA_RESOLUTION:
/* expressed in hundredths */
/* Fontmetrics give two fields: sXDeviceRes and sYDeviceRes */
/* in pels/inch for bitmap fonts, notional units/Em for outline */
if (logfonts[(LONG)font_struct->fid].fm.fsDefn & FM_DEFN_OUTLINE) {
/* Em size gives point size */
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.sXDeviceRes* fm.lEmInc* 100;
} else {
/* multiply by number of points in one inch, 72, + 100ths */
*value_return = (unsigned long)
logfonts[(LONG)font_struct->fid].fm.sXDeviceRes * 722818;
}
return True;
break;
default:
return False;
break;
}
}
/*
*----------------------------------------------------------------------
*
* TkOS2ScaleFont --
*
* Adapted from "OS/2 Presentation Manager Programming" by Petzold.
* Called to scale a presentation space's font to a desired size.
*
* Results:
* Return true if successful.
*
* Side effects:
* Sets the character box attribute of a presentation space.
*
*----------------------------------------------------------------------
*/
BOOL
TkOS2ScaleFont(hps, pointSize, pointWidth)
HPS hps;
ULONG pointSize; /* in decipixels */
ULONG pointWidth; /* 0 means "same as pointSize" */
{
HDC hdc;
LONG xRes, yRes;
POINTL points[2];
SIZEF sizef;
/* If pointWidth defaulted, set it to pointSize */
if (pointWidth == 0) {
pointWidth = pointSize;
}
/* Determine device and its resolutions */
hdc = GpiQueryDevice(hps);
if (hdc == HDC_ERROR) {
return FALSE;
} else if (hdc == NULLHANDLE) {
/* No device context associated, assume the screen */
xRes = aDevCaps[CAPS_HORIZONTAL_FONT_RES];
yRes = aDevCaps[CAPS_VERTICAL_FONT_RES];
} else {
rc = DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 1, &xRes);
if (rc != TRUE) {
xRes = aDevCaps[CAPS_HORIZONTAL_FONT_RES];
}
rc = DevQueryCaps(hdc, CAPS_VERTICAL_FONT_RES, 1, &yRes);
if (rc != TRUE) {
yRes = aDevCaps[CAPS_VERTICAL_FONT_RES];
}
}
FIX_RES(xRes);
FIX_RES(yRes);
/*
* Determine desired point size in pixels with device resolution.
* Font resolution is returned by PM in pels per inch, device resolution
* is in dots per inch. 722.818 decipoints in an inch.
* Add 361.409 for correct rounding.
*/
points[0].x = 0;
points[0].y = 0;
points[1].x = (xRes * pointWidth + 361.409) / 722.818;
points[1].y = (yRes * pointSize + 361.409) / 722.818;
/* Convert to page coordinates */
rc = GpiConvert(hps, CVTC_DEVICE, CVTC_PAGE, 2L, points);
/* Now set the character box */
sizef.cx = MAKEFIXED((points[1].x - points[0].x), 0);
sizef.cy = MAKEFIXED((points[1].y - points[0].y), 0);
return GpiSetCharBox(hps, &sizef);
}