home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tcltk805.zip
/
tcl805s.zip
/
tk8.0.5
/
os2
/
tkOS2Font.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-09-08
|
88KB
|
2,301 lines
/*
* tkOS2Font.c --
*
* Contains the OS/2 implementation of the platform-independant
* font package interface.
*
* Copyright (c) 1996-2000 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"
#include "tkFont.h"
/*
* The following structure represents OS/2's implementation of a font.
*/
typedef struct OS2Font {
TkFont font; /* Stuff used by generic font package. Must
* be first in structure. */
LONG fontID; /* OS/2 "handle" to font. */
HWND hwnd; /* Toplevel window of application that owns
* this font, used for getting HPS. */
} OS2Font;
/*
* The following structure is used as to map between the Tcl strings
* that represent the system fonts and the numbers used by Windows and OS/2.
*/
#define OS2_SYSTEM_FONT 0
#define OS2_SYSTEM_MONO_FONT 1
#define OS2_SYSTEM_PROP_FONT 2
#define OS2_SYSTEM_SANS_FONT 3
/*
#define WIN_ANSI_FIXED_FONT 100
#define WIN_ANSI_VAR_FONT 101
#define WIN_DEVICE_DEFAULT_FONT 102
#define WIN_OEM_FIXED_FONT 103
#define WIN_SYSTEM_FIXED_FONT 104
#define WIN_SYSTEM_FONT 105
*/
static TkStateMap systemMap[] = {
/*
{WIN_ANSI_FIXED_FONT, "ansifixed"},
{WIN_ANSI_VAR_FONT, "ansi"},
{WIN_DEVICE_DEFAULT_FONT, "device"},
{WIN_OEM_FIXED_FONT, "oemfixed"},
{WIN_SYSTEM_FIXED_FONT, "systemfixed"},
{WIN_SYSTEM_FONT, "system"},
*/
{OS2_SYSTEM_FONT, "System"},
{OS2_SYSTEM_MONO_FONT, "System Monospaced"},
{OS2_SYSTEM_PROP_FONT, "System Proportional"},
{OS2_SYSTEM_SANS_FONT, "WarpSans"},
{OS2_SYSTEM_MONO_FONT, "ansifixed"},
{OS2_SYSTEM_PROP_FONT, "ansi"},
{OS2_SYSTEM_FONT, "device"},
{OS2_SYSTEM_MONO_FONT, "oemfixed"},
{OS2_SYSTEM_MONO_FONT, "systemfixed"},
{OS2_SYSTEM_FONT, "system"},
{-1, NULL}
};
/*
* The following structure is used as to map between the numbers that
* represent the system fonts and the numbers used by Windows to the
* names of fonts that are needed for succesful calling of GpiCreateLogFont.
*/
static TkStateMap nameMap[] = {
{OS2_SYSTEM_FONT, "System"},
{OS2_SYSTEM_MONO_FONT, "System Monospaced"},
{OS2_SYSTEM_PROP_FONT, "System Proportional"},
{OS2_SYSTEM_SANS_FONT, "WarpSans"},
/*
{WIN_ANSI_FIXED_FONT, "System Monospaced"},
{WIN_ANSI_VAR_FONT, "System Proportional"},
{WIN_DEVICE_DEFAULT_FONT, "System"},
{WIN_OEM_FIXED_FONT, "System Monospaced"},
{WIN_SYSTEM_FIXED_FONT, "System Monospaced"},
{WIN_SYSTEM_FONT, "System"},
*/
{-1, NULL}
};
#define ABS(x) (((x) < 0) ? -(x) : (x))
/*
* Forward declarations for functions used in this file.
*/
static TkFont * AllocFont _ANSI_ARGS_((TkFont *tkFontPtr,
Tk_Window tkwin, LONG fontID));
/*
* 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
/*
* 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. 72.2818 decipoints in an inch.
* Add 36.1409 for correct rounding.
* aDevCaps[CAPS_VERTICAL_FONT_RES] is vertical font resolution in pels per
* inch
*/
#ifdef IGNOREPMRES
/*
* Requested by Ilya Zakharevich:
* 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.2818 + 36.1409) / overrideResolution) \
: (((pixels) * 72.2818 + 36.1409) / aDevCaps[CAPS_VERTICAL_FONT_RES]) \
)
#define POINTTOPIX(points) ( \
(aDevCaps[CAPS_VERTICAL_FONT_RES] == 120) \
? (((points) * overrideResolution + 36.1409) / 72.2818) \
: (((points) * aDevCaps[CAPS_VERTICAL_FONT_RES] + 36.1409) / 72.2818) \
)
#define PTOP(p) ( \
(aDevCaps[CAPS_VERTICAL_FONT_RES] == 120) \
? (((p) * overrideResolution + 60) / 120 ) \
: (p) \
)
#define FIX_RES(res) (if (res==120) {res = overrideResolution})
#else
#define PIXTOPOINT(pixels) \
(((pixels) * 72.2818 + 36.1409) / aDevCaps[CAPS_VERTICAL_FONT_RES])
#define POINTTOPIX(points) \
(((points) * aDevCaps[CAPS_VERTICAL_FONT_RES] + 36.1409) / 72.2818)
#define PTOP(p) (p)
#define FIX_RES(res)
#endif
/*
* Quotes from GPI Guide and Reference:
* "Font Data structures and Attributes"
* [...]
* The value of Em height represents the font point size in world coordinates
* and is the same as the character cell height. For an outline font, this can
* be set by the character cell height attribute.
* [...]
* The maximum baseline extent for a font is the sum of the maximum ascender
* and the maximum descender. Maximum baseline extent is not equal to cell
* height for outline fonts, but is for image fonts."
* "FATTRS Data structure
* [...]
* The maximum baseline extent is the vertical space occupied by the
* characters in the font. If you are setting the font-use indicator
* FATTR_FONTUSE_OUTLINE, you should set the maximum baseline extent to 0.
* Outline fonts take an equivalent value from the character cell attribute
* that is current when text is written to an output device.
* The maximum baseline extent is required to select an image font and must be
* specified in world coordinates.
* [...]
* The maximum baseline extent in the FATTRS data structure is used for
* programming, unlike the maximum baseline extent in the FONTMETRICS data
* structure, which is only a measurement as recommended by the font's
* designer."
*/
/*
*---------------------------------------------------------------------------
*
* TkpGetNativeFont --
*
* Map a platform-specific native font name to a TkFont.
*
* Results:
* The return value is a pointer to a TkFont that represents the
* native font. If a native font by the given name could not be
* found, the return value is NULL.
*
* Every call to this procedure returns a new TkFont structure,
* even if the name has already been seen before. The caller should
* call TkpDeleteFont() when the font is no longer needed.
*
* The caller is responsible for initializing the memory associated
* with the generic TkFont when this function returns and releasing
* the contents of the generic TkFont before calling TkpDeleteFont().
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
TkFont *
TkpGetNativeFont(tkwin, name)
Tk_Window tkwin; /* For display where font will be used. */
CONST char *name; /* Platform-specific font name. */
{
int object;
char *fontName;
FATTRS fattrs;
LONG lFontID= nextLogicalFont;
LONG match;
TkFont *tkFont;
#ifdef VERBOSE
printf("TkpGetNativeFont (%s), tkwin %x\n", name, tkwin);
#endif
if (lFontID > MAX_LID) {
/* We can't simultaneously use more than MAX_LID fonts */
#ifdef VERBOSE
printf(" => too many font IDs\n");
#endif
return (TkFont *) NULL;
}
object = TkFindStateNum(NULL, NULL, systemMap, name);
if (object < 0) {
#ifdef VERBOSE
printf(" => object < 0\n");
#endif
return NULL;
}
fontName = TkFindStateString(nameMap, object);
if (fontName == NULL) {
#ifdef VERBOSE
printf(" => fontName NULL\n");
#endif
return NULL;
}
#ifdef VERBOSE
printf(" => fontName %s\n", fontName);
#endif
fattrs.usRecordLength = (USHORT)sizeof(FATTRS);
fattrs.fsSelection = 0;
fattrs.lMatch = 0L;
strncpy(fattrs.szFacename, fontName, FACESIZE);
fattrs.idRegistry = 0; /* Unknown */
fattrs.usCodePage = 0; /* Use present codepage */
fattrs.lMaxBaselineExt = 0L;
fattrs.lAveCharWidth = 0L;
fattrs.fsType = 0;
fattrs.fsFontUse = 0;
/*
* Replace the standard X, Mac and Windows family names with the names that
* OS/2 likes.
*/
if ((stricmp(fattrs.szFacename, "Times") == 0)
|| (stricmp(fattrs.szFacename, "New York") == 0)) {
strcpy(fattrs.szFacename, "Times New Roman");
} else if ((stricmp(fattrs.szFacename, "Courier New") == 0)
|| (stricmp(fattrs.szFacename, "Monaco") == 0)) {
strcpy(fattrs.szFacename, "Courier");
} else if ((stricmp(fattrs.szFacename, "Arial") == 0)
|| (stricmp(fattrs.szFacename, "Geneva") == 0)) {
strcpy(fattrs.szFacename, "Helvetica");
}
match = GpiCreateLogFont(globalPS, NULL, lFontID, &fattrs);
WinReleasePS(globalPS);
if (match == GPI_ERROR) {
#ifdef VERBOSE
printf("GpiCreateLogFont %s (%x, id %d) ERROR, error %x\n",
fattrs.szFacename, globalPS, lFontID,
WinGetLastError(TclOS2GetHAB()));
#endif
return (TkFont *)NULL;
}
#ifdef VERBOSE
printf(" GpiCreateLogFont %s (%x, id %d) OK, match %d\n",
fattrs.szFacename, globalPS, lFontID, match);
#endif
memcpy((void *)&logfonts[lFontID].fattrs, (void *)&fattrs, sizeof(fattrs));
logfonts[lFontID].fattrs.lMatch = match;
tkFont = AllocFont(NULL, tkwin, lFontID);
if (tkFont != NULL) {
nextLogicalFont++;
}
return tkFont;
}
/*
*---------------------------------------------------------------------------
*
* TkpGetFontFromAttributes --
*
* Given a desired set of attributes for a font, find a font with
* the closest matching attributes.
*
* Results:
* The return value is a pointer to a TkFont that represents the
* font with the desired attributes. If a font with the desired
* attributes could not be constructed, some other font will be
* substituted automatically. NULL is never returned.
*
* Every call to this procedure returns a new TkFont structure,
* even if the specified attributes have already been seen before.
* The caller should call TkpDeleteFont() to free the platform-
* specific data when the font is no longer needed.
*
* The caller is responsible for initializing the memory associated
* with the generic TkFont when this function returns and releasing
* the contents of the generic TkFont before calling TkpDeleteFont().
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
TkFont *
TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr)
TkFont *tkFontPtr; /* If non-NULL, store the information in
* this existing TkFont structure, rather than
* allocating a new structure to hold the
* font; the existing contents of the font
* will be released. If NULL, a new TkFont
* structure is allocated. */
Tk_Window tkwin; /* For display where font will be used. */
CONST TkFontAttributes *faPtr; /* Set of attributes to match. */
{
LONG lFontID= nextLogicalFont;
Window window;
HWND hwnd;
HPS hps;
LONG match = 0;
BOOL useIntended = FALSE;
LONG reqFonts, remFonts;
PFONTMETRICS os2fonts;
BOOL found = FALSE;
LONG outline = -1;
LONG font = 0;
int i, error = 30000, best = -1;
TkFont *tkFont;
char caseName[FACESIZE];
int faceLen = 0;
#ifdef VERBOSE
printf("TkpGetFontFromAttributes (%s), tkwin %x\n", faPtr->family, tkwin);
#endif
if (lFontID > MAX_LID) {
/* We can't simultaneously use more than MAX_LID fonts */
lFontID = MAX_LID;
goto defaultFont;
}
window = Tk_WindowId(((TkWindow *) tkwin)->mainPtr->winPtr);
hwnd = (window == None) ? HWND_DESKTOP : TkOS2GetHWND(window);
hps = WinGetPS(hwnd);
/*
* Watch out: we are called with all-lowercase font name!
* => check to see if there's a font with the same name when using
* stricmp but different when using strcmp.
*/
if (faPtr->family != NULL) {
/* Determine total number of fonts */
reqFonts = 0L;
remFonts = GpiQueryFonts(hps, QF_PUBLIC, NULL, &reqFonts,
(LONG) sizeof(FONTMETRICS), NULL);
#ifdef VERBOSE
printf(" nr.of fonts: %ld\n", remFonts);
#endif
/* Allocate space for the fonts */
os2fonts = (PFONTMETRICS) ckalloc(remFonts * sizeof(FONTMETRICS));
if (os2fonts == NULL) {
WinReleasePS(hps);
goto defaultFont;
}
/* Retrieve the fonts */
reqFonts = remFonts;
remFonts = GpiQueryFonts(hps, QF_PUBLIC, NULL, &reqFonts,
(LONG) sizeof(FONTMETRICS), os2fonts);
#ifdef VERBOSE
printf(" got %d (%d remaining)\n", reqFonts, remFonts);
#endif
caseName[0] = '\0';
for (i=0; i<reqFonts; i++) {
if ((strcmp(faPtr->family, os2fonts[i].szFacename) != 0)
&& (stricmp(faPtr->family, os2fonts[i].szFacename) == 0)) {
strcpy(caseName, os2fonts[i].szFacename);
#ifdef VERBOSE
printf(" => case sensitive name [%s]\n", caseName);
#endif
}
#ifdef VERBOSE
printf("m%d, Em %d (nom %ddpt, lMBE %d) res %dx%d %s %s face[%s]%s, fam[%s]%s\n",
os2fonts[i].lMatch, os2fonts[i].lEmHeight,
os2fonts[i].sNominalPointSize, os2fonts[i].lMaxBaselineExt,
os2fonts[i].sXDeviceRes, os2fonts[i].sYDeviceRes,
(os2fonts[i].fsType & FM_TYPE_FIXED) ? "fix" : "prop",
(os2fonts[i].fsDefn & FM_DEFN_OUTLINE) ? "outl" : "bmp",
os2fonts[i].szFacename,
(os2fonts[i].fsType & FM_TYPE_FACETRUNC) ? " (trunc()" : "",
os2fonts[i].szFamilyname,
(os2fonts[i].fsType & FM_TYPE_FAMTRUNC) ? " (trunc()" : "");
#endif
}
ckfree((char *)os2fonts);
}
/* Set defaults in logfont */
logfonts[lFontID].fattrs.usRecordLength = (USHORT)sizeof(FATTRS);
logfonts[lFontID].fattrs.fsSelection = (USHORT)0;
logfonts[lFontID].fattrs.lMatch = 0L;
if (faPtr->family == NULL) {
memset(logfonts[lFontID].fattrs.szFacename, '\0', FACESIZE);
} else if (caseName[0] != '\0') {
strncpy(logfonts[lFontID].fattrs.szFacename, caseName, FACESIZE);
} else {
strncpy(logfonts[lFontID].fattrs.szFacename, faPtr->family, 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].fattrs.lMaxBaselineExt = 12;
/*
* A negative number for faPtr->pointsize means pixel size,
* 0 means default font size
*/
if (faPtr->pointsize < 0) {
logfonts[lFontID].fattrs.lMaxBaselineExt = -(faPtr->pointsize);
logfonts[lFontID].deciPoints = 10 * PIXTOPOINT(-faPtr->pointsize);
#ifdef VERBOSE
printf("pixel size %d, deciPoints %d\n",
logfonts[lFontID].fattrs.lMaxBaselineExt,
logfonts[lFontID].deciPoints);
#endif
} else {
logfonts[lFontID].fattrs.lMaxBaselineExt = POINTTOPIX(faPtr->pointsize);
if (faPtr->pointsize == 0) {
logfonts[lFontID].deciPoints = 120;
} else {
logfonts[lFontID].deciPoints = 10 * faPtr->pointsize;
}
#ifdef VERBOSE
printf("point size %d => pixel size %d, deciPoints %d\n",
faPtr->pointsize, logfonts[lFontID].fattrs.lMaxBaselineExt,
logfonts[lFontID].deciPoints);
#endif
}
/* Determine additional selection criteria */
/* If the name already contains "Bold" then don't specify that */
if (faPtr->weight == TK_FW_BOLD &&
(strstr(logfonts[lFontID].fattrs.szFacename, "Bold") == NULL)) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_BOLD;
#ifdef VERBOSE
printf("FATTR_SEL_BOLD\n");
#endif
}
/* If the name already contains "Italic" then don't specify that */
if (faPtr->slant == TK_FS_ITALIC &&
(strstr(logfonts[lFontID].fattrs.szFacename, "Italic") == NULL)) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_ITALIC;
#ifdef VERBOSE
printf("FATTR_SEL_ITALIC\n");
#endif
}
if (faPtr->underline != 0) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_UNDERSCORE;
#ifdef VERBOSE
printf("FATTR_SEL_UNDERSCORE\n");
#endif
}
if (faPtr->overstrike != 0) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_STRIKEOUT;
#ifdef VERBOSE
printf("FATTR_SEL_STRIKEOUT\n");
#endif
}
/*
* Replace the standard X, Mac and Windows family names with the names that
* OS/2 likes.
*/
if ((stricmp(logfonts[lFontID].fattrs.szFacename, "Times") == 0)
|| (stricmp(logfonts[lFontID].fattrs.szFacename, "New York") == 0)) {
strcpy(logfonts[lFontID].fattrs.szFacename, "Times New Roman");
} else if ((stricmp(logfonts[lFontID].fattrs.szFacename, "Courier New")== 0)
|| (stricmp(logfonts[lFontID].fattrs.szFacename, "Monaco") == 0)) {
strcpy(logfonts[lFontID].fattrs.szFacename, "Courier");
} else if ((stricmp(logfonts[lFontID].fattrs.szFacename, "Arial") == 0)
|| (stricmp(logfonts[lFontID].fattrs.szFacename, "Geneva") == 0)) {
strcpy(logfonts[lFontID].fattrs.szFacename, "Helvetica");
} 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;
char *name = faPtr->family;
if (name != NULL && sscanf(name, "%d.%n", &l, &off) && off > 0) {
int fields;
#ifdef VERBOSE
printf(" trying Presentation Parameters-notation font\n");
printf(" d %d, n %d\n", l, off);
#endif
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);
#ifdef VERBOSE
printf(" sscanf returns %d, off %d\n", fields, off);
#endif
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);
#ifdef VERBOSE
printf(" font [%s] last part\n", name);
#endif
} else {
#ifdef VERBOSE
printf(" decomposing [%s]\n", name);
#endif
/* There are attributes after the fontname */
name += off;
while (TRUE) {
if (strnicmp(name, ".bold", 5) == 0) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_BOLD;
#ifdef VERBOSE
printf(" .bold -> FATTR_SEL_BOLD\n");
#endif
name += 5;
} else if (strnicmp(name, ".italic", 7) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_ITALIC;
#ifdef VERBOSE
printf(" .italic -> FATTR_SEL_ITALIC\n");
#endif
name += 7;
} else if (strnicmp(name, ".underline", 10) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_UNDERSCORE;
#ifdef VERBOSE
printf(" .underline -> FATTR_SEL_UNDERSCORE\n");
#endif
name += 10;
} else if (strnicmp(name, ".strikeout", 10) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_STRIKEOUT;
#ifdef VERBOSE
printf(" .strikeout -> FATTR_SEL_STRIKEOUT\n");
#endif
name += 10;
} else if (strnicmp(name, ".outline", 8) == 0) {
logfonts[lFontID].fattrs.fsSelection
|= FATTR_SEL_OUTLINE;
#ifdef VERBOSE
printf(" .outline -> FATTR_SEL_OUTLINE\n");
#endif
name += 8;
} else if (*name == '.') {
name++;
break;
} else {
break;
}
}
}
} else if (name != NULL) {
l = strlen(name);
if (l > FACESIZE - 1) {
l = FACESIZE - 1;
}
if (caseName[0] != '\0') {
strncpy(logfonts[lFontID].fattrs.szFacename, caseName, l);
} else {
strncpy(logfonts[lFontID].fattrs.szFacename, name, l);
}
}
}
/*
* If we have to use an outline font (instead of a bitmap font) that we
* ask for with an unqualified name (eg. Courier) and specifying we want
* a bold or italic font, then we can get the situation where we select
* the normal font because it comes before the bold version (eg. Courier
* outline has match 46 on my system, while Courier Bold has 47), and
* selecting the non-bold version with FATTR_SEL_BOLD doesn't give us the
* bold version. Hoping for standard specifications in normal fonts, I'll
* add " Bold" and/or " Italic" here if they're not already in the name.
*/
faceLen = strlen(caseName);
if ((logfonts[lFontID].fattrs.fsSelection & FATTR_SEL_BOLD) &&
strstr(logfonts[lFontID].fattrs.szFacename, "Bold") == NULL) {
strncat(logfonts[lFontID].fattrs.szFacename, " Bold",
FACESIZE - 1 - strlen(logfonts[lFontID].fattrs.szFacename));
}
if ((logfonts[lFontID].fattrs.fsSelection & FATTR_SEL_ITALIC) &&
strstr(logfonts[lFontID].fattrs.szFacename, "Italic") == NULL) {
strncat(logfonts[lFontID].fattrs.szFacename, " Italic",
FACESIZE - 1 - strlen(logfonts[lFontID].fattrs.szFacename));
}
#ifdef VERBOSE
printf(" trying font [%s]\n", logfonts[lFontID].fattrs.szFacename);
#endif
/* Name has now been filled in with a correct or sane value */
/* Determine number of fonts */
reqFonts = 0L;
remFonts = GpiQueryFonts(hps, QF_PUBLIC,
logfonts[lFontID].fattrs.szFacename, &reqFonts,
(LONG) sizeof(FONTMETRICS), NULL);
#ifdef VERBOSE
printf(" nr.of fonts: %d\n", remFonts);
#endif
reqFonts = remFonts;
if (reqFonts) {
/* Allocate space for the fonts */
os2fonts = (PFONTMETRICS) ckalloc(remFonts * sizeof(FONTMETRICS));
if (os2fonts == NULL) {
WinReleasePS(hps);
goto defaultFont;
}
/* Get the fonts that apply */
remFonts = GpiQueryFonts(hps, QF_PUBLIC,
logfonts[lFontID].fattrs.szFacename, &reqFonts,
(LONG) sizeof(FONTMETRICS), os2fonts);
#ifdef VERBOSE
if (remFonts == GPI_ALTERROR) {
printf(" GpiQueryFonts %s ERROR %x\n", logfonts[lFontID].fattrs.szFacename,
WinGetLastError(TclOS2GetHAB()));
} else {
printf(" nr.of fonts [%s]: %d (%d remaining)\n",
logfonts[lFontID].fattrs.szFacename, reqFonts, remFonts);
}
#endif
} 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.
*/
#ifdef VERBOSE
printf(" trying %s font %s (%ddp, lMaxBaselineExt %d), match %d\n",
(os2fonts[i].fsDefn & FM_DEFN_OUTLINE) ? "outline" : "fixed",
os2fonts[i].szFacename, os2fonts[i].sNominalPointSize,
os2fonts[i].lMaxBaselineExt, os2fonts[i].lMatch);
#endif
if (os2fonts[i].fsDefn & FM_DEFN_OUTLINE) {
/* Remember we found an outline font */
outline = i;
#ifdef VERBOSE
printf(" found outline font %s, match %d\n",
os2fonts[i].szFacename, os2fonts[i].lMatch);
#endif
} else {
/* Bitmap font, check size, type, resolution */
int cerror = 0, err1;
/*
* Note: FONTMETRICS.fsSelection can contain FM_SEL_ISO9241_TESTED,
* FATTRS.fsSelection cannot.
*/
#ifdef VERBOSE
printf("m%d, Em %d (nom %ddpt, lMBE %d), xR %d, yR %d, %s, %s, face[%s]%s, fam[%s]%s\n",
os2fonts[i].lMatch, os2fonts[i].lEmHeight,
os2fonts[i].sNominalPointSize, os2fonts[i].lMaxBaselineExt,
os2fonts[i].sXDeviceRes, os2fonts[i].sYDeviceRes,
(os2fonts[i].fsType & FM_TYPE_FIXED) ? "fix" : "prop",
(os2fonts[i].fsDefn & FM_DEFN_OUTLINE) ? "outl" : "bmp",
os2fonts[i].szFacename,
(os2fonts[i].fsType & FM_TYPE_FACETRUNC) ? " (trunc()" : "",
os2fonts[i].szFamilyname,
(os2fonts[i].fsType & FM_TYPE_FAMTRUNC) ? " (trunc()" : "");
#endif
/*
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;
*/
#ifdef VERBOSE
printf(" useInt %d, os2f.sNom %d, os2f.lMBE %d, logf.lMBE %d\n",
useIntended, os2fonts[i].sNominalPointSize,
os2fonts[i].lMaxBaselineExt * 10,
logfonts[lFontID].fattrs.lMaxBaselineExt * 10);
#endif
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;
}
#ifdef VERBOSE
if (found) printf(" found bitmap font %s, match %d (size %d)\n",
os2fonts[i].szFacename, os2fonts[i].lMatch,
os2fonts[i].lMaxBaselineExt);
/*
} else { if (os2fonts[i].sNominalPointSize !=
logfonts[lFontID].fattrs.lMaxBaselineExt * 10) {
if (os2fonts[i].sNominalPointSize !=
logfonts[lFontID].fattrs.lMaxBaselineExt * 10) {
printf(" height %d doesn't match required %d\n",
os2fonts[i].sNominalPointSize,
logfonts[lFontID].fattrs.lMaxBaselineExt * 10);
*/
if (os2fonts[i].lMaxBaselineExt !=
logfonts[lFontID].fattrs.lMaxBaselineExt) {
printf(" height %d doesn't match required %d\n",
os2fonts[i].lMaxBaselineExt,
logfonts[lFontID].fattrs.lMaxBaselineExt);
} else if (os2fonts[i].sXDeviceRes !=
aDevCaps[CAPS_HORIZONTAL_FONT_RES]) {
printf(" hor. device res %d doesn't match required %d\n",
os2fonts[i].sXDeviceRes,
aDevCaps[CAPS_HORIZONTAL_FONT_RES]);
} else if (os2fonts[i].sYDeviceRes !=
aDevCaps[CAPS_VERTICAL_FONT_RES]) {
printf(" vert. device res %d doesn't match required %d\n",
os2fonts[i].sYDeviceRes,
aDevCaps[CAPS_VERTICAL_FONT_RES]);
} else if ( logfonts[lFontID].fattrs.fsFontUse
& FATTR_FONTUSE_TRANSFORMABLE) {
printf(" transformations require outline font\n");
}
#endif
}
}
/* 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;
#ifdef VERBOSE
printf(" using outline font %s, match %d\n",
os2fonts[font].szFacename, os2fonts[font].lMatch);
#endif
}
/* 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 */
#ifdef VERBOSE
printf("XLoadFont trying default font\n");
#endif
memset(logfonts[lFontID].fattrs.szFacename, '\0', FACESIZE);
match= GpiCreateLogFont(hps, NULL, lFontID,
&(logfonts[lFontID].fattrs));
if (match == GPI_ERROR) {
if (os2fonts) {
ckfree((char *)os2fonts);
}
WinReleasePS(hps);
goto defaultFont;
} else if (match == FONT_DEFAULT) {
FONTMETRICS fm;
rc= GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm);
if (!rc) {
WinReleasePS(hps);
goto defaultFont;
}
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);
}
WinReleasePS(hps);
goto defaultFont;
} else {
logfonts[lFontID].fattrs.idRegistry = os2fonts[font].idRegistry;
logfonts[lFontID].fattrs.usCodePage = os2fonts[font].usCodePage;
logfonts[lFontID].fattrs.lMaxBaselineExt=os2fonts[font].lMaxBaselineExt;
logfonts[lFontID].fattrs.lAveCharWidth = os2fonts[font].lAveCharWidth;
/*
* NOTE: values for fsSelection and fsType in FONTMETRICS and FATTRS
* differ, so check for each supported value.
*/
if (os2fonts[font].fsSelection & FM_SEL_ITALIC) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_ITALIC;
}
if (os2fonts[font].fsSelection & FM_SEL_UNDERSCORE) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_UNDERSCORE;
}
if (os2fonts[font].fsSelection & FM_SEL_OUTLINE) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_OUTLINE;
}
if (os2fonts[font].fsSelection & FM_SEL_STRIKEOUT) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_STRIKEOUT;
}
if (os2fonts[font].fsSelection & FM_SEL_BOLD) {
logfonts[lFontID].fattrs.fsSelection |= FATTR_SEL_BOLD;
}
if (os2fonts[font].fsType & FM_TYPE_KERNING) {
logfonts[lFontID].fattrs.fsType |= FATTR_TYPE_KERNING;
}
if (os2fonts[font].fsType & FM_TYPE_MBCS) {
logfonts[lFontID].fattrs.fsType |= FATTR_TYPE_MBCS;
}
if (os2fonts[font].fsType & FM_TYPE_DBCS) {
logfonts[lFontID].fattrs.fsType |= FATTR_TYPE_DBCS;
}
/* Nothing to determine FATTR_TYPE_ANTIALIASED ? */
logfonts[lFontID].fattrs.fsFontUse = 0;
if (os2fonts[font].fsCapabilities & FM_CAP_NOMIX) {
logfonts[lFontID].fattrs.fsFontUse |= FATTR_FONTUSE_NOMIX;
}
if (os2fonts[font].fsDefn & FM_DEFN_OUTLINE) {
logfonts[lFontID].fattrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
/*
logfonts[lFontID].fattrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
*/
}
logfonts[lFontID].fattrs.lMatch = match;
if (logfonts[lFontID].outline == TRUE) {
logfonts[lFontID].fattrs.lMaxBaselineExt = 0;
logfonts[lFontID].fattrs.lAveCharWidth = 0;
}
strcpy(logfonts[lFontID].fattrs.szFacename, os2fonts[font].szFacename);
#ifdef VERBOSE
printf(" using match %d (%s)\n", match,
logfonts[lFontID].fattrs.szFacename);
#endif
}
got_it:
#ifdef VERBOSE
printf("m %d len %d sel %x reg %d cp %d mbe %d acw %d sel %x tp %x fu %x\n",
logfonts[lFontID].fattrs.lMatch,
logfonts[lFontID].fattrs.usRecordLength,
logfonts[lFontID].fattrs.fsSelection,
logfonts[lFontID].fattrs.idRegistry,
logfonts[lFontID].fattrs.usCodePage,
logfonts[lFontID].fattrs.lMaxBaselineExt,
logfonts[lFontID].fattrs.lAveCharWidth,
logfonts[lFontID].fattrs.fsSelection,
logfonts[lFontID].fattrs.fsType, logfonts[lFontID].fattrs.fsFontUse);
#endif
rc = GpiCreateLogFont(hps, NULL, lFontID, &(logfonts[lFontID].fattrs));
WinReleasePS(hps);
if (rc == GPI_ERROR) {
#ifdef VERBOSE
printf("GpiCreateLogFont %x recL %d sel %d m %d n %s r %d cp %d lMBE %d lACW %d t %x fu %x ERROR, error %x\n",
hps, logfonts[lFontID].fattrs.usRecordLength,
logfonts[lFontID].fattrs.fsSelection,
logfonts[lFontID].fattrs.lMatch,
logfonts[lFontID].fattrs.szFacename,
logfonts[lFontID].fattrs.idRegistry,
logfonts[lFontID].fattrs.usCodePage,
logfonts[lFontID].fattrs.lMaxBaselineExt,
logfonts[lFontID].fattrs.lAveCharWidth,
logfonts[lFontID].fattrs.fsType,
logfonts[lFontID].fattrs.fsFontUse,
WinGetLastError(TclOS2GetHAB()));
#endif
WinReleasePS(hps);
goto defaultFont;
}
#ifdef VERBOSE
printf("GpiCreateLogFont %x recL %d sel %d m %d n %s r %d cp %d lMBE %d lACW %d t %d fu %d %s (%d)\n",
hps, logfonts[lFontID].fattrs.usRecordLength,
logfonts[lFontID].fattrs.fsSelection,
logfonts[lFontID].fattrs.lMatch,
logfonts[lFontID].fattrs.szFacename,
logfonts[lFontID].fattrs.idRegistry,
logfonts[lFontID].fattrs.usCodePage,
logfonts[lFontID].fattrs.lMaxBaselineExt,
logfonts[lFontID].fattrs.lAveCharWidth,
logfonts[lFontID].fattrs.fsType,
logfonts[lFontID].fattrs.fsFontUse,
rc == FONT_MATCH ? "FONT_MATCH"
: (rc == FONT_DEFAULT ? "FONT_DEFAULT" : "??"), rc);
#endif
tkFont = AllocFont(tkFontPtr, tkwin, lFontID);
if (tkFont != NULL) {
nextLogicalFont++;
return tkFont;
}
/* We have to return some font in case of an error */
defaultFont:
window = Tk_WindowId(((TkWindow *) tkwin)->mainPtr->winPtr);
hwnd = (window == None) ? HWND_DESKTOP : TkOS2GetHWND(window);
hps = WinGetPS(hwnd);
/* 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;
logfonts[lFontID].setShear = FALSE;
logfonts[lFontID].outline = FALSE;
logfonts[lFontID].deciPoints = 120;
logfonts[lFontID].fattrs.lMaxBaselineExt = 12;
match= GpiCreateLogFont(hps, NULL, lFontID, &(logfonts[lFontID].fattrs));
WinReleasePS(hps);
tkFont = AllocFont(tkFontPtr, tkwin, lFontID);
return tkFont;
}
/*
*---------------------------------------------------------------------------
*
* TkpDeleteFont --
*
* Called to release a font allocated by TkpGetNativeFont() or
* TkpGetFontFromAttributes(). The caller should have already
* released the fields of the TkFont that are used exclusively by
* the generic TkFont code.
*
* Results:
* None.
*
* Side effects:
* TkFont is deallocated.
*
*---------------------------------------------------------------------------
*/
void
TkpDeleteFont(tkFontPtr)
TkFont *tkFontPtr; /* Token of font to be deleted. */
{
HPS hps;
OS2Font *fontPtr;
fontPtr = (OS2Font *) tkFontPtr;
hps = WinGetPS(fontPtr->hwnd);
GpiDeleteSetId(hps, fontPtr->fontID);
WinReleasePS(hps);
ckfree((char *) fontPtr);
}
/*
*---------------------------------------------------------------------------
*
* TkpGetFontFamilies --
*
* Return information about the font families that are available
* on the display of the given window.
*
* Results:
* interp->result is modified to hold a list of all the available
* font families.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
void
TkpGetFontFamilies(interp, tkwin)
Tcl_Interp *interp; /* Interp to hold result. */
Tk_Window tkwin; /* For display to query. */
{
Window window;
HWND hwnd;
HPS hps;
PFONTMETRICS os2fonts;
LONG reqFonts, remFonts;
int i;
window = Tk_WindowId(tkwin);
hwnd = (window == (Window) NULL) ? HWND_DESKTOP : TkOS2GetHWND(window);
hps = WinGetPS(hwnd);
/* Determine total number of fonts */
reqFonts = 0L;
remFonts = GpiQueryFonts(hps, QF_PUBLIC, NULL, &reqFonts,
(LONG) sizeof(FONTMETRICS), NULL);
#ifdef VERBOSE
printf("TkpGetFontFamilies, nr.of fonts: %d\n", remFonts);
#endif
/* Allocate space for the fonts */
os2fonts = (PFONTMETRICS) ckalloc(remFonts * sizeof(FONTMETRICS));
if (os2fonts == NULL) {
return;
}
/* Retrieve the fonts */
reqFonts = remFonts;
remFonts = GpiQueryFonts(hps, QF_PUBLIC, NULL, &reqFonts,
(LONG) sizeof(FONTMETRICS), os2fonts);
#ifdef VERBOSE
printf(" got %d (%d remaining)\n", reqFonts, remFonts);
#endif
for (i=0; i<reqFonts; i++) {
#ifdef VERBOSE
printf("m%d, Em %d, nom %ddpt, lMBE %d, res %dx%d, %s, %s, face[%s]%s, fam[%s]%s\n",
os2fonts[i].lMatch, os2fonts[i].lEmHeight,
os2fonts[i].sNominalPointSize, os2fonts[i].lMaxBaselineExt,
os2fonts[i].sXDeviceRes, os2fonts[i].sYDeviceRes,
(os2fonts[i].fsType & FM_TYPE_FIXED) ? "fix" : "prop",
(os2fonts[i].fsDefn & FM_DEFN_OUTLINE) ? "outl" : "bmp",
os2fonts[i].szFacename,
(os2fonts[i].fsType & FM_TYPE_FACETRUNC) ? " (trunc()" : "",
os2fonts[i].szFamilyname,
(os2fonts[i].fsType & FM_TYPE_FAMTRUNC) ? " (trunc()" : "");
#endif
if (os2fonts[i].fsType & FM_TYPE_FAMTRUNC) {
char fullName[MAX_FLEN];
rc = WinQueryAtomName(WinQuerySystemAtomTable(),
os2fonts[i].FaceNameAtom, (PSZ)&fullName,
MAX_FLEN);
if (rc != 0) {
#ifdef VERBOSE
printf("WinQueryAtomName OK: %s\n", fullName);
#endif
if (rc >= 256) {
fullName[255] = '\0';
}
Tcl_AppendElement(interp, fullName);
} else {
#ifdef VERBOSE
printf("WinQueryAtomName ERROR %d\n",
WinGetLastError(TclOS2GetHAB()));
#endif
Tcl_AppendElement(interp, os2fonts[i].szFamilyname);
}
} else {
Tcl_AppendElement(interp, os2fonts[i].szFamilyname);
}
}
ckfree((char *)os2fonts);
WinReleasePS(hps);
}
/*
*---------------------------------------------------------------------------
*
* Tk_MeasureChars --
*
* Determine the number of characters from the string that will fit
* in the given horizontal span. The measurement is done under the
* assumption that Tk_DrawChars() will be used to actually display
* the characters.
*
* Results:
* The return value is the number of characters from source that
* fit into the span that extends from 0 to maxLength. *lengthPtr is
* filled with the x-coordinate of the right edge of the last
* character that did fit.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
int
Tk_MeasureChars(tkfont, source, numChars, maxLength, flags, lengthPtr)
Tk_Font tkfont; /* Font in which characters will be drawn. */
CONST char *source; /* Characters to be displayed. Need not be
* '\0' terminated. */
int numChars; /* Maximum number of characters to consider
* from source string. */
int maxLength; /* If > 0, maxLength specifies the longest
* permissible line length; don't consider any
* character that would cross this
* x-position. If <= 0, then line length is
* unbounded and the flags argument is
* ignored. */
int flags; /* Various flag bits OR-ed together:
* TK_PARTIAL_OK means include the last char
* which only partially fit on this line.
* TK_WHOLE_WORDS means stop on a word
* boundary, if possible.
* TK_AT_LEAST_ONE means return at least one
* character even if no characters fit. */
int *lengthPtr; /* Filled with x-location just after the
* terminating character. */
{
OS2Font *fontPtr;
HPS hps;
LONG oldFont;
POINTL aSize[TXTBOX_COUNT];
int curX = 0, curIdx = 0;
int l, tmpNumChars;
char *str;
fontPtr = (OS2Font *) tkfont;
#ifdef VERBOSE
printf("Tk_MeasureChars [%s] (%d), maxLength %d, font ID [%d]\n", source,
numChars, maxLength, fontPtr->fontID);
#endif
hps = WinGetPS(fontPtr->hwnd);
oldFont = GpiQueryCharSet(hps);
rc = GpiCreateLogFont(hps, NULL, fontPtr->fontID,
&logfonts[fontPtr->fontID].fattrs);
#ifdef VERBOSE
if (rc == GPI_ERROR) {
printf(" GpiCreateLogFont %s hps %x, id %d (match %d) ERROR %x\n",
logfonts[fontPtr->fontID].fattrs.szFacename, hps,
fontPtr->fontID, logfonts[fontPtr->fontID].fattrs.lMatch,
WinGetLastError(TclOS2GetHAB()));
} else {
printf(" GpiCreateLogFont %s hps %x, id %d (match %d) OK: %d\n",
logfonts[fontPtr->fontID].fattrs.szFacename, hps,
fontPtr->fontID, logfonts[fontPtr->fontID].fattrs.lMatch, rc);
}
#endif
GpiSetCharSet(hps, fontPtr->fontID);
/* If this is an outline font, set the char box */
if (logfonts[fontPtr->fontID].outline) {
#ifdef VERBOSE
SIZEF charBox;
#endif
rc = TkOS2ScaleFont(hps, logfonts[fontPtr->fontID].deciPoints, 0);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("TkOS2ScaleFont %d ERROR %x\n",
logfonts[fontPtr->fontID].deciPoints,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("TkOS2ScaleFont %d OK\n",
logfonts[fontPtr->fontID].deciPoints);
}
rc = GpiQueryCharBox(hps, &charBox);
if (rc!=TRUE) {
printf("GpiQueryCharBox ERROR %x\n");
} else {
printf("GpiQueryCharBox OK: now cx %d (%d,%d), cy %d (%d,%d)\n",
charBox.cx, FIXEDINT(charBox.cx), FIXEDFRAC(charBox.cx),
charBox.cy, FIXEDINT(charBox.cy), FIXEDFRAC(charBox.cy));
}
#endif
}
if (numChars == 0) {
curX = 0;
curIdx = 0;
} else if (maxLength <= 0) {
/* only 512 bytes allowed in string */
for (tmpNumChars = numChars, str = (char *)source, curX = curIdx = 0;
tmpNumChars > 0;
tmpNumChars -= 512, str += 512) {
l = tmpNumChars > 512 ? 512 : tmpNumChars;
rc = GpiQueryTextBox(hps, l, (PCH)str, TXTBOX_COUNT, aSize);
#ifdef VERBOSE
if (rc != TRUE) {
printf(" GpiQueryTextBox [%s] (%d) ERROR %x\n", str, l,
WinGetLastError(TclOS2GetHAB()));
} else {
printf(" GpiQueryTextBox [%s] (%d) OK: %d + %d\n", str, l,
curX,aSize[TXTBOX_CONCAT].x- aSize[TXTBOX_BOTTOMLEFT].x);
}
#endif
curX += aSize[TXTBOX_CONCAT].x - aSize[TXTBOX_BOTTOMLEFT].x;
curIdx += l;
}
#ifdef VERBOSE
printf(" maxLength <= 0; curX %d, curIdx %d\n", curX, curIdx);
#endif
} else {
int localMax, max;
int *partials;
partials = (int *) ckalloc(numChars * sizeof (int));
/*
* For each number of chars upto numChars see if it is shorter
* than maxLength.
* GpiQueryTextBox (and GpiCharString*At) only allow 512 bytes in
* string; check each chunk of 512 separately, so we don't do the
* chunking upto numChars times.
*/
memset((VOID *)partials, 0, numChars * sizeof (int));
max = 0;
for (tmpNumChars = numChars, str = (char *)source;
tmpNumChars > 0;
tmpNumChars -= 512, str += 512) {
/* Check from 0 to tmpNumChars or 512 additional chars */
l = tmpNumChars > 512 ? 512 : tmpNumChars;
#ifdef VERBOSE
printf("tmpNumChars %d, str %x, l %d\n", tmpNumChars, str, l);
#endif
for (localMax= 0; localMax<l; localMax++) {
rc = GpiQueryTextBox(hps, localMax+1, (PCH)str, TXTBOX_COUNT,
aSize);
partials[max] += aSize[TXTBOX_CONCAT].x
- aSize[TXTBOX_BOTTOMLEFT].x;
#ifdef VERBOSE
if (rc != TRUE) {
printf("GpiQueryTextBox [%s] (%d) ERROR %x\n", str,
localMax, WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiQueryTextBox [%s] (%d): %d partials[%d] %d\n",
str, localMax,
aSize[TXTBOX_CONCAT].x - aSize[TXTBOX_BOTTOMLEFT].x,
max, partials[max]);
}
#endif
if (partials[max] > maxLength) {
/* Stop outer loop by making tmpNumChars not > 0 */
tmpNumChars = -1;
break;
}
max++;
}
/* Carry present maximum forward for next chunk of 512 */
if (max < numChars - 1) {
int newval = partials[max];
#ifdef VERBOSE
printf("memset partials+%d+1 to partials[%d] (%d) for %d\n",
max, max, newval, numChars - max - 1);
#endif
memset((VOID *)(partials+max+1), newval,
(numChars - max - 1) * sizeof (int));
}
}
/* only 512 bytes allowed in string */
/*
for (max= 0; max<numChars; max++) {
partials[max] = 0;
for (tmpNumChars = numChars, str = (char *)source;
tmpNumChars > 0;
tmpNumChars -= 512, str += 512) {
l = tmpNumChars > 512 ? 512 : tmpNumChars;
rc = GpiQueryTextBox(hps, l, (PCH)str, TXTBOX_COUNT, aSize);
partials[max] += aSize[TXTBOX_CONCAT].x
- aSize[TXTBOX_BOTTOMLEFT].x;
#ifdef VERBOSE
if (rc != TRUE) {
printf("GpiQueryTextBox [%s] (%d) ERROR %x\n", str, l,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiQueryTextBox [%s] (%d): %d p[%d] %d curIdx %d\n",
str, l, aSize[TXTBOX_CONCAT].x
- aSize[TXTBOX_BOTTOMLEFT].x, partials[max], curIdx);
}
#endif
}
if (partials[max] > maxLength) {
break;
}
}
*/
if ((flags & TK_WHOLE_WORDS) && max < numChars) {
int sawSpace;
int index;
sawSpace = 0;
index = max;
while (index >= 0 && !isspace(source[index])) {
--index;
}
while (index >= 0 && isspace(source[index])) {
sawSpace = 1;
--index;
}
/*
* If a space char was not found, and the flag for forcing
* at least on (or more) chars to be drawn is false, then
* set MAX to zero so no text is drawn. Otherwise, if a
* space was found, set max to be one char past the space.
*/
if ((index < 0) && !(flags & TK_AT_LEAST_ONE)) {
max = 0;
} else if (sawSpace) {
max = index + 1;
}
}
if (max == 0) {
curX = 0;
} else {
curX = partials[max - 1];
}
if (((flags & TK_PARTIAL_OK) && max < numChars && curX < maxLength)
|| ((flags & TK_AT_LEAST_ONE) && max == 0 && numChars > 0)) {
/*
* We want to include the first character that didn't
* quite fit. Call the function again to include the
* width of the extra character.
*/
/* only 512 bytes allowed in string */
for (tmpNumChars = numChars, str = (char *)source;
tmpNumChars > 0;
tmpNumChars -= 512, str += 512) {
l = tmpNumChars > 512 ? 512 : tmpNumChars;
rc = GpiQueryTextBox(hps, l, (PCH)str, TXTBOX_COUNT, aSize);
#ifdef VERBOSE
if (rc != TRUE) {
printf(" GpiQueryTextBox [%s] (%d) ERROR %x\n", str, l,
WinGetLastError(TclOS2GetHAB()));
} else {
printf(" GpiQueryTextBox [%s] (%d) OK %d + %d\n", str, l,
curX, aSize[TXTBOX_CONCAT].x
- aSize[TXTBOX_BOTTOMLEFT].x);
}
#endif
curX += aSize[TXTBOX_CONCAT].x - aSize[TXTBOX_BOTTOMLEFT].x;
}
++max;
}
ckfree((char *) partials);
curIdx = max;
#ifdef VERBOSE
printf(" curX %d, curIdx %d\n", curX, curIdx);
#endif
}
GpiSetCharSet(hps, oldFont);
WinReleasePS(hps);
#ifdef VERBOSE
printf("Tk_MeasureChars [%s] (%d), maxLength %d returns x %d (%d chars)\n",
source, numChars, maxLength, curX, curIdx);
#endif
*lengthPtr = curX;
return curIdx;
}
/*
*---------------------------------------------------------------------------
*
* Tk_DrawChars --
*
* Draw a string of characters on the screen.
*
* Results:
* None.
*
* Side effects:
* Information gets drawn on the screen.
*
*---------------------------------------------------------------------------
*/
void
Tk_DrawChars(display, drawable, gc, tkfont, source, numChars, x, y)
Display *display; /* Display on which to draw. */
Drawable drawable; /* Window or pixmap in which to draw. */
GC gc; /* Graphics context for drawing characters. */
Tk_Font tkfont; /* Font in which characters will be drawn;
* must be the same as font used in GC. */
CONST char *source; /* Characters to be displayed. Need not be
* '\0' terminated. All Tk meta-characters
* (tabs, control characters, and newlines)
* should be stripped out of the string that
* is passed to this function. If they are
* not stripped out, they will be displayed as
* regular printing characters. */
int numChars; /* Number of characters in string. */
int x, y; /* Coordinates at which to place origin of
* string when drawing. */
{
HPS hps;
LONG oldFont = 0L;
LONG oldHorAlign, oldVerAlign;
LONG oldBackMix;
LONG oldColor, oldBackColor = 0L;
POINTL oldRefPoint;
LONG oldPattern;
HBITMAP oldBitmap;
POINTL aPoints[3]; /* Lower-left, upper-right, lower-left source */
CHARBUNDLE cBundle;
LONG windowHeight;
int l, tmpNumChars;
char *str;
POINTL refPoint;
TkOS2PSState state;
OS2Font *fontPtr;
fontPtr = (OS2Font *) gc->font;
display->request++;
if (drawable == None) {
return;
}
#ifdef VERBOSE
printf("Tk_DrawChars [%s] (%d) at (%d,%d) font [%d], GC %x (fs %s, s %x)\n",
source, numChars, x, y, fontPtr->fontID, gc,
gc->fill_style == FillStippled ? "FillStippled" :
(gc->fill_style == FillOpaqueStippled ? "FillOpaqueStippled" :
(gc->fill_style == FillSolid ? "FillSolid" :
(gc->fill_style == FillTiled ? "FillTiled" : "UNKNOWN"))));
#endif
hps = TkOS2GetDrawablePS(display, drawable, &state);
GpiSetMix(hps, tkpOS2MixModes[gc->function]);
/*
* Translate the Y coordinates to PM coordinates.
* X Window System y-coordinate is the position of the baseline like
* in PM, so we don't have to take the height of the characters into
* consideration.
*/
windowHeight = TkOS2WindowHeight((TkOS2Drawable *)drawable);
#ifdef VERBOSE
printf(" x %d, y %d (PM: %d)\n", x, y, windowHeight - y);
#endif
y = windowHeight - y;
if ((gc->fill_style == FillStippled
|| gc->fill_style == FillOpaqueStippled)
&& (gc->stipple != None)) {
TkOS2Drawable *todPtr = (TkOS2Drawable *)gc->stipple;
HDC dcMem;
HPS psMem;
DEVOPENSTRUC dop = {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
SIZEL sizl = {0,0}; /* use same page size as device */
HBITMAP bitmap;
BITMAPINFOHEADER2 bmpInfo;
RECTL rect;
POINTL textBox[TXTBOX_COUNT];
#ifdef VERBOSE
printf("Tk_DrawChars stippled \"%s\" (%x) at %d,%d fg %d bg %d bmp %x\n",
source, gc->stipple, x, y, gc->foreground, gc->background,
todPtr->bitmap.handle);
#endif
if (todPtr->type != TOD_BITMAP) {
panic("unexpected drawable type in stipple");
}
/*
* Select stipple pattern into destination PS.
* gc->ts_x_origin and y_origin are relative to origin of the
* destination drawable, while PatternRefPoint is in world coords.
*/
dcMem = DevOpenDC(TclOS2GetHAB(), OD_MEMORY, (PSZ)"*", 5L,
(PDEVOPENDATA)&dop, NULLHANDLE);
if (dcMem == DEV_ERROR) {
#ifdef VERBOSE
printf("DevOpenDC ERROR %x in Tk_DrawChars\n",
WinGetLastError(TclOS2GetHAB()));
#endif
return;
}
#ifdef VERBOSE
printf("DevOpenDC in Tk_DrawChars returns %x\n", dcMem);
#endif
psMem = GpiCreatePS(TclOS2GetHAB(), dcMem, &sizl,
PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
if (psMem == GPI_ERROR) {
#ifdef VERBOSE
printf("GpiCreatePS ERROR %x in Tk_DrawChars\n",
WinGetLastError(TclOS2GetHAB()));
#endif
DevCloseDC(dcMem);
return;
}
#ifdef VERBOSE
printf("GpiCreatePS in Tk_DrawChars returns %x\n", psMem);
#endif
/*
* Compute the bounding box and create a compatible bitmap.
*/
rc = WinQueryWindowRect(((TkOS2Drawable *)drawable)->bitmap.parent,
&rect);
#ifdef VERBOSE
if (rc != TRUE) {
printf("WinQueryWindowRect ERROR %x\n",
WinGetLastError(TclOS2GetHAB()));
} else {
printf("WinQueryWindowRect OK %d,%d->%d,%d\n", rect.xLeft,
rect.yBottom, rect.xRight, rect.yTop);
}
#endif
bmpInfo.cbFix = 16L;
/*
bmpInfo.cx = rect.xRight - rect.xLeft;
bmpInfo.cy = rect.yTop - rect.yBottom;
*/
bmpInfo.cx = xScreen;
bmpInfo.cy = yScreen;
bmpInfo.cPlanes = 1;
bmpInfo.cBitCount= display->screens[display->default_screen].root_depth;
bitmap = GpiCreateBitmap(psMem, &bmpInfo, 0L, NULL, NULL);
#ifdef VERBOSE
if (bitmap == GPI_ERROR) {
printf("GpiCreateBitmap (%d,%d) GPI_ERROR %x\n", bmpInfo.cx,
bmpInfo.cy, WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiCreateBitmap (%d,%d) returned %x\n", bmpInfo.cx,
bmpInfo.cy, bitmap);
}
#endif
oldBitmap = GpiSetBitmap(psMem, bitmap);
#ifdef VERBOSE
if (bitmap == HBM_ERROR) {
printf("GpiSetBitmap (%x) HBM_ERROR %x\n", bitmap,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetBitmap %x returned %x\n", bitmap, oldBitmap);
}
#endif
refPoint.x = gc->ts_x_origin;
refPoint.y = windowHeight - gc->ts_y_origin;
#ifdef VERBOSE
printf("gc->ts_x_origin=%d (->%d), gc->ts_y_origin=%d (->%d)\n",
gc->ts_x_origin, refPoint.x, gc->ts_y_origin, refPoint.y);
#endif
/* The bitmap mustn't be selected in the HPS */
TkOS2SetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
refPoint.x, refPoint.y, &oldPattern, &oldRefPoint);
GpiQueryTextAlignment(psMem, &oldHorAlign, &oldVerAlign);
GpiSetTextAlignment(psMem, TA_LEFT, TA_BASE);
GpiQueryAttrs(psMem, PRIM_CHAR, LBB_COLOR, (PBUNDLE)&cBundle);
cBundle.lColor = gc->foreground;
rc = GpiSetAttrs(psMem, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiSetAttrs textColor %d ERROR %x\n", cBundle.lColor,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetAttrs textColor %d OK\n", cBundle.lColor);
}
#endif
oldBackMix = GpiQueryBackMix(psMem);
rc = GpiSetBackMix(psMem, BM_LEAVEALONE);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiSetBackMix ERROR %x\n", WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetBackMix OK\n");
}
#endif
oldBackColor = GpiQueryBackColor(psMem);
GpiSetBackColor(psMem, CLR_FALSE);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiSetBackColor CLR_FALSE ERROR %x\n",
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetBackColor CLR_FALSE OK\n");
}
#endif
if (fontPtr->fontID != None) {
rc = GpiCreateLogFont(psMem, NULL, fontPtr->fontID,
&(logfonts[fontPtr->fontID].fattrs));
#ifdef VERBOSE
if (rc!=GPI_ERROR) {
printf("GpiCreateLogFont (%x, id %d) OK\n", psMem,
fontPtr->fontID);
} else {
printf("GpiCreateLogFont (%x, id %d) ERROR, error %x\n", psMem,
fontPtr->fontID, WinGetLastError(TclOS2GetHAB()));
}
#endif
oldFont = GpiQueryCharSet(psMem);
#ifdef VERBOSE
if (rc==LCID_ERROR) {
printf("GpiQueryCharSet ERROR %x\n",
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiQueryCharSet OK\n");
}
#endif
rc = GpiSetCharSet(psMem, fontPtr->fontID);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiSetCharSet (%x, id %d, face [%s]) ERROR, error %x\n",
psMem, fontPtr->fontID,
logfonts[fontPtr->fontID].fattrs.szFacename,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetCharSet (%x, id %d, face [%s]) OK\n", psMem,
fontPtr->fontID,
logfonts[fontPtr->fontID].fattrs.szFacename);
}
#endif
/* If this is an outline font, set the char box */
if (logfonts[fontPtr->fontID].outline) {
#ifdef VERBOSE
SIZEF charBox;
#endif
rc = TkOS2ScaleFont(psMem, logfonts[fontPtr->fontID].deciPoints,
0);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("TkOS2ScaleFont %d ERROR %x\n",
logfonts[fontPtr->fontID].deciPoints,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("TkOS2ScaleFont %d OK\n",
logfonts[fontPtr->fontID].deciPoints);
}
rc = GpiQueryCharBox(psMem, &charBox);
if (rc!=TRUE) {
printf("GpiQueryCharBox ERROR %x\n");
} else {
printf("GpiQueryCharBox OK: now cx %d (%d,%d), cy %d (%d,%d)\n",
charBox.cx, FIXEDINT(charBox.cx),
FIXEDFRAC(charBox.cx), charBox.cy,
FIXEDINT(charBox.cy), FIXEDFRAC(charBox.cy));
}
#endif
}
aPoints[0].y = -fontPtr->font.fm.descent;
} else {
FONTMETRICS fm;
rc = GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm);
aPoints[0].y = -fm.lMaxDescender;
if (fm.fsDefn & FM_DEFN_OUTLINE) {
/* Scale the value */
aPoints[0].y *= fm.lEmHeight;
aPoints[0].y /= 12;
}
}
refPoint.x = x;
refPoint.y = y;
rc = GpiSetCurrentPosition(psMem, &refPoint);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiSetCurrentPosition %d,%d ERROR %x\n", refPoint.x,
refPoint.y, WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetCurrentPosition %d,%d OK\n", refPoint.x, refPoint.y);
}
#endif
/* only 512 bytes allowed in string */
aPoints[0].x = refPoint.x;
aPoints[0].y += refPoint.y;
aPoints[1].x = refPoint.x;
aPoints[1].y = refPoint.y;
aPoints[2].x = aPoints[0].x;
aPoints[2].y = aPoints[0].y;
for (tmpNumChars = numChars, str = (char *)source; tmpNumChars > 0;
tmpNumChars -= 512, str += 512) {
l = tmpNumChars > 512 ? 512 : tmpNumChars;
rc = GpiQueryTextBox(psMem, l, (PCH)str, TXTBOX_COUNT, textBox);
#ifdef VERBOSE
if (rc != TRUE) {
printf("GpiQueryTextBox \"%s\" (%d) ERROR %x\n", str, l,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiQueryTextBox \"%s\" (%d) OK: %d, refPoint (%d,%d)\n",
str, l,
textBox[TXTBOX_CONCAT].x - textBox[TXTBOX_BOTTOMLEFT].x,
refPoint.x, refPoint.y);
}
#endif
aPoints[1].x += textBox[TXTBOX_CONCAT].x
- textBox[TXTBOX_BOTTOMLEFT].x;
}
aPoints[1].y += textBox[TXTBOX_TOPRIGHT].y;
#ifdef VERBOSE
printf("aPoints: %d,%d %d,%d <- %d,%d\n", aPoints[0].x, aPoints[0].y,
aPoints[1].x, aPoints[1].y, aPoints[2].x, aPoints[2].y);
#endif
/*
* The following code is tricky because fonts are rendered in multiple
* colors. First we draw onto a black background and copy the white
* bits. Then we draw onto a white background and copy the black bits.
* Both the foreground and background bits of the font are ANDed with
* the stipple pattern as they are copied.
*/
rc = GpiBitBlt(psMem, (HPS)0, 2, aPoints, ROP_ZERO, BBO_IGNORE);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiBitBlt ZERO %d,%d ERROR %x\n", aPoints[0].x,
aPoints[0].y, WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiBitBlt ZERO %d,%d OK\n", aPoints[0].x, aPoints[0].y);
}
#endif
rc = GpiSetCurrentPosition(psMem, &refPoint);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiSetCurrentPosition %d,%d ERROR %x\n", refPoint.x,
refPoint.y, WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetCurrentPosition %d,%d OK\n", refPoint.x, refPoint.y);
}
#endif
/* only 512 bytes allowed in string */
l = numChars;
str = (char *)source;
while (numChars>512) {
rc = GpiCharString(psMem, l, (PCH)str);
#ifdef VERBOSE
if (rc==GPI_ERROR) {
printf("GpiCharString [%s] ERROR %x\n", str,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiCharString [%s] OK\n", str);
}
#endif
l -= 512;
str += 512;
}
rc = GpiCharString(psMem, l, (PCH)str);
#ifdef VERBOSE
if (rc==GPI_ERROR) {
printf("GpiCharString [%s] ERROR %x\n", str,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiCharString [%s] OK\n", str);
}
#endif
rc = GpiBitBlt(hps, psMem, 3, aPoints, (LONG)0x00ea, BBO_IGNORE);
#ifdef VERBOSE
if (rc==GPI_ERROR) {
printf("GpiBitBlt ERROR %x\n", WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiBitBlt OK\n");
}
#endif
rc = GpiBitBlt(psMem, (HPS)0, 2, aPoints, ROP_ONE, BBO_IGNORE);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiBitBlt ONE %d,%d ERROR %x\n", aPoints[0].x, aPoints[0].y,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiBitBlt ONE %d,%d OK\n", aPoints[0].x, aPoints[0].y);
}
#endif
/* only 512 bytes allowed in string */
rc = GpiSetCurrentPosition(psMem, &refPoint);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiSetCurrentPosition %d, %d ERROR %x\n", refPoint.x,
refPoint.y, WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetCurrentPosition %d,%d OK\n", refPoint.x, refPoint.y);
}
#endif
l = numChars;
str = (char *)source;
while (numChars>512) {
rc = GpiCharString(psMem, 512, (PCH)str);
#ifdef VERBOSE
if (rc==GPI_ERROR) {
printf("GpiCharString ERROR %x\n", WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiCharString OK\n");
}
#endif
l -= 512;
str += 512;
}
rc = GpiCharString(psMem, l, (PCH)str);
#ifdef VERBOSE
if (rc==GPI_ERROR) {
printf("GpiCharString ERROR %x\n", WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiCharString OK\n");
}
#endif
/*
rc = GpiBitBlt(hps, psMem, 3, aPoints, (LONG)0x00ba, BBO_IGNORE);
*/
rc = GpiBitBlt(hps, psMem, 3, aPoints, (LONG)0x008a, BBO_IGNORE);
#ifdef VERBOSE
if (rc==GPI_ERROR) {
printf("GpiBitBlt ERROR %x\n", WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiBitBlt OK\n");
}
#endif
/*
* Destroy the temporary bitmap and restore the device context.
*/
GpiSetBitmap(psMem, oldBitmap);
GpiDeleteBitmap(bitmap);
GpiDestroyPS(psMem);
DevCloseDC(dcMem);
if (fontPtr->fontID != None) {
rc = GpiSetCharSet(hps, oldFont);
}
rc = GpiSetBackMix(hps, oldBackMix);
/* The bitmap must be reselected in the HPS */
TkOS2UnsetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
oldPattern, &oldRefPoint);
} else {
GpiQueryTextAlignment(hps, &oldHorAlign, &oldVerAlign);
GpiSetTextAlignment(hps, TA_LEFT, TA_BASE);
GpiQueryAttrs(hps, PRIM_CHAR, LBB_COLOR, (PBUNDLE)&cBundle);
oldColor = cBundle.lColor;
cBundle.lColor = gc->foreground;
rc = GpiSetAttrs(hps, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("GpiSetAttrs color %x ERROR %x\n", gc->foreground,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("GpiSetAttrs color %x OK\n", gc->foreground);
}
#endif
oldBackMix = GpiQueryBackMix(hps);
GpiSetBackMix(hps, BM_LEAVEALONE);
if (fontPtr->fontID != None) {
rc = GpiCreateLogFont(hps, NULL, fontPtr->fontID,
&(logfonts[fontPtr->fontID].fattrs));
#ifdef VERBOSE
if (rc!=GPI_ERROR) {
printf("GpiCreateLogFont (%x, id %d, match %d) OK\n", hps,
fontPtr->fontID,
logfonts[fontPtr->fontID].fattrs.lMatch);
} else {
printf("GpiCreateLogFont (%x, id %d, match %d) ERROR %x\n", hps,
fontPtr->fontID, logfonts[fontPtr->fontID].fattrs.lMatch,
WinGetLastError(TclOS2GetHAB()));
}
#endif
oldFont = GpiQueryCharSet(hps);
rc = GpiSetCharSet(hps, fontPtr->fontID);
#ifdef VERBOSE
if (rc==TRUE) {
printf("GpiSetCharSet (%x, id %d, %s) OK\n", hps,
fontPtr->fontID,
logfonts[fontPtr->fontID].fattrs.szFacename);
} else {
printf("GpiSetCharSet (%x, id %d, %s) ERROR, error %x\n", hps,
fontPtr->fontID,
logfonts[fontPtr->fontID].fattrs.szFacename,
WinGetLastError(TclOS2GetHAB()));
}
#endif
/* If this is an outline font, set the char box */
if (logfonts[fontPtr->fontID].outline) {
#ifdef VERBOSE
SIZEF charBox;
#endif
rc = TkOS2ScaleFont(hps, logfonts[fontPtr->fontID].deciPoints,
0);
#ifdef VERBOSE
if (rc!=TRUE) {
printf("TkOS2ScaleFont %d ERROR %x\n",
logfonts[fontPtr->fontID].deciPoints,
WinGetLastError(TclOS2GetHAB()));
} else {
printf("TkOS2ScaleFont %d OK\n",
logfonts[fontPtr->fontID].deciPoints);
}
rc = GpiQueryCharBox(hps, &charBox);
if (rc!=TRUE) {
printf("GpiQueryCharBox ERROR %x\n");
} else {
printf("GpiQueryCharBox OK now cx%d (%d,%d) cy%d (%d,%d)\n",
charBox.cx, FIXEDINT(charBox.cx),
FIXEDFRAC(charBox.cx), charBox.cy,
FIXEDINT(charBox.cy), FIXEDFRAC(charBox.cy));
}
#endif
}
}
refPoint.x = x;
refPoint.y = y;
/* only 512 bytes allowed in string */
rc = GpiSetCurrentPosition(hps, &refPoint);
#ifdef VERBOSE
if (rc==TRUE) {
printf("GpiSetCurrentPosition %d,%d OK\n", refPoint.x, refPoint.y);
} else {
printf("GpiSetCurrentPosition %d,%d ERROR %x\n", refPoint.x,
refPoint.y, WinGetLastError(TclOS2GetHAB()));
}
#endif
l = numChars;
str = (char *)source;
while (l>512) {
rc = GpiCharString(hps, 512, (PCH)str);
#ifdef VERBOSE
if (rc==GPI_OK) {
printf("GpiCharString returns GPI_OK\n");
} else {
printf("GpiCharString returns %d, ERROR %x\n", rc,
WinGetLastError(TclOS2GetHAB()));
}
#endif
l -= 512;
str += 512;
}
rc = GpiCharString(hps, l, (PCH)str);
#ifdef VERBOSE
if (rc==GPI_OK) {
printf("GpiCharString returns GPI_OK\n");
} else {
printf("GpiCharString returns %d, ERROR %x\n", rc,
WinGetLastError(TclOS2GetHAB()));
}
#endif
rc = GpiSetCharSet(hps, LCID_DEFAULT);
#ifdef VERBOSE
if (rc==TRUE) {
printf("GpiSetCharSet (%x, default) OK\n", hps);
} else {
printf("GpiSetCharSet (%x, default) ERROR, error %x\n", hps,
WinGetLastError(TclOS2GetHAB()));
}
#endif
rc = GpiDeleteSetId(hps, fontPtr->fontID);
#ifdef VERBOSE
if (rc==TRUE) {
printf("GpiDeleteSetId (%x, id %d) OK\n", hps, fontPtr->fontID);
} else {
printf("GpiDeleteSetId (%x, id %d) ERROR, error %x\n", hps,
fontPtr->fontID, WinGetLastError(TclOS2GetHAB()));
}
#endif
if (fontPtr->fontID != None) {
GpiSetCharSet(hps, oldFont);
}
GpiSetBackMix(hps, oldBackMix);
GpiSetBackColor(hps, oldBackColor);
cBundle.lColor = oldColor;
GpiSetAttrs(hps, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
GpiSetTextAlignment(hps, oldHorAlign, oldVerAlign);
}
TkOS2ReleaseDrawablePS(drawable, hps, &state);
}
/*
*---------------------------------------------------------------------------
*
* AllocFont --
*
* Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
* Allocates and intializes the memory for a new TkFont that
* wraps the platform-specific data.
*
* Results:
* Returns pointer to newly constructed TkFont.
*
* The caller is responsible for initializing the fields of the
* TkFont that are used exclusively by the generic TkFont code, and
* for releasing those fields before calling TkpDeleteFont().
*
* Side effects:
* Memory allocated.
*
*---------------------------------------------------------------------------
*/
static TkFont *
AllocFont(tkFontPtr, tkwin, fontID)
TkFont *tkFontPtr; /* If non-NULL, store the information in
* this existing TkFont structure, rather than
* allocating a new structure to hold the
* font; the existing contents of the font
* will be released. If NULL, a new TkFont
* structure is allocated. */
Tk_Window tkwin; /* For display where font will be used. */
LONG fontID; /* Windows information about font. */
{
HWND hwnd;
OS2Font *fontPtr;
HPS hps;
ULONG oldFont;
FONTMETRICS fm;
Window window;
TkFontAttributes *faPtr;
#ifdef VERBOSE
printf("AllocFont id %d\n", fontID);
#endif
if (tkFontPtr != NULL) {
fontPtr = (OS2Font *) tkFontPtr;
hps = WinGetPS(fontPtr->hwnd);
GpiDeleteSetId(hps, fontPtr->fontID);
WinReleasePS(hps);
} else {
fontPtr = (OS2Font *) ckalloc(sizeof(OS2Font));
}
window = Tk_WindowId(((TkWindow *) tkwin)->mainPtr->winPtr);
hwnd = (window == None) ? HWND_DESKTOP : TkOS2GetHWND(window);
hps = WinGetPS(hwnd);
oldFont = GpiQueryCharSet(hps);
rc = GpiCreateLogFont(hps, NULL, fontID, &logfonts[fontID].fattrs);
#ifdef VERBOSE
if (rc == GPI_ERROR) {
printf(" GpiCreateLogFont %s hps %x, id %d (match %d) ERROR %x\n",
logfonts[fontID].fattrs.szFacename, hps, fontID,
logfonts[fontID].fattrs.lMatch, WinGetLastError(TclOS2GetHAB()));
} else {
printf(" GpiCreateLogFont %s hps %x, id %d (match %d) OK: %d\n",
logfonts[fontID].fattrs.szFacename, hps, fontID,
logfonts[fontID].fattrs.lMatch, rc);
}
#endif
GpiSetCharSet(hps, fontID);
rc = GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm);
fontPtr->font.fid = (Font) fontPtr;
faPtr = &fontPtr->font.fa;
faPtr->family = Tk_GetUid(fm.szFacename);
faPtr->pointsize = fm.lEmHeight;
faPtr->weight = (fm.usWeightClass > 5) ? TK_FW_BOLD : TK_FW_NORMAL;
faPtr->slant = (fm.fsSelection & FM_SEL_ITALIC) ? TK_FS_ITALIC
: TK_FS_ROMAN;
faPtr->underline = (fm.fsSelection & FM_SEL_UNDERSCORE) ? 1 : 0;
faPtr->overstrike = (fm.fsSelection & FM_SEL_STRIKEOUT) ? 1 : 0;
fontPtr->font.fm.ascent = fm.lMaxAscender;
fontPtr->font.fm.descent = fm.lMaxDescender;
fontPtr->font.fm.maxWidth = fm.lMaxCharInc;
fontPtr->font.fm.fixed = (fm.fsType & FM_TYPE_FIXED);
logfonts[fontID].outline = (fm.fsDefn & FM_DEFN_OUTLINE);
if (logfonts[fontID].outline) {
/* Scale the values */
#ifdef VERBOSE
printf("Set scaling %s ascent %d->%d descent %d->%d maxWidth %d->%d\n",
logfonts[fontID].fattrs.szFacename, fontPtr->font.fm.ascent,
fontPtr->font.fm.ascent * logfonts[fontID].deciPoints / 120,
fontPtr->font.fm.descent,
fontPtr->font.fm.descent * logfonts[fontID].deciPoints / 120,
fontPtr->font.fm.maxWidth,
fontPtr->font.fm.maxWidth * logfonts[fontID].deciPoints / 120);
#endif
fontPtr->font.fm.ascent *= logfonts[fontID].deciPoints;
fontPtr->font.fm.ascent /= 120;
fontPtr->font.fm.descent *= logfonts[fontID].deciPoints;
fontPtr->font.fm.descent /= 120;
fontPtr->font.fm.maxWidth *= logfonts[fontID].deciPoints;
fontPtr->font.fm.maxWidth /= 120;
}
GpiSetCharSet(hps, oldFont);
WinReleasePS(hps);
fontPtr->fontID = fontID;
fontPtr->hwnd = hwnd;
return (TkFont *) fontPtr;
}
/*
*----------------------------------------------------------------------
*
* 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;
#ifdef VERBOSE
printf("TkOS2ScaleFont hps %x, pointSize %d, pointWidth %d\n", hps,
pointSize, pointWidth);
rc = GpiQueryCharBox(hps, &sizef);
if (rc!=TRUE) printf("GpiQueryCharBox ERROR %x\n",
WinGetLastError(TclOS2GetHAB()));
else printf("GpiQueryCharBox OK: cx %d (%d,%d), cy %d (%d,%d)\n", sizef.cx,
FIXEDINT(sizef.cx), FIXEDFRAC(sizef.cx), sizef.cy,
FIXEDINT(sizef.cy), FIXEDFRAC(sizef.cy));
#endif
/* If pointWidth defaulted, set it to pointSize */
if (pointWidth == 0) {
pointWidth = pointSize;
}
/* Determine device and its resolutions */
hdc = GpiQueryDevice(hps);
if (hdc == HDC_ERROR) {
#ifdef VERBOSE
printf(" GpiQueryDevice ERROR %x\n",
WinGetLastError(TclOS2GetHAB()));
#endif
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) {
#ifdef VERBOSE
printf(" DevQueryCaps xRes ERROR %x\n",
WinGetLastError(TclOS2GetHAB()));
#endif
xRes = aDevCaps[CAPS_HORIZONTAL_FONT_RES];
}
rc = DevQueryCaps(hdc, CAPS_VERTICAL_FONT_RES, 1, &yRes);
if (rc != TRUE) {
#ifdef VERBOSE
printf(" DevQueryCaps yRes ERROR %x\n",
WinGetLastError(TclOS2GetHAB()));
#endif
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);
#ifdef VERBOSE
if (rc!=TRUE) printf("GpiConvert ERROR %x\n",
WinGetLastError(TclOS2GetHAB()));
else printf("GpiConvert OK: (%d,%d) -> (%d,%d)\n",
(aDevCaps[CAPS_HORIZONTAL_FONT_RES] * pointWidth + 360) / 720,
(aDevCaps[CAPS_VERTICAL_FONT_RES] * pointSize + 360) / 720,
points[1].x, points[1].y);
#endif
/* 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);
#ifdef VERBOSE
printf("after GpiConvert: cx FIXED(%d), cy FIXED(%d)\n",
points[1].x - points[0].x, points[1].y - points[0].y);
#endif
return GpiSetCharBox(hps, &sizef);
}