home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
-
- #ifdef NDEBUG
- #define LOG(format, args...)
- #else
- FILE *logfile;
- #define LOG(format, args...) \
- fprintf (logfile, "%s:%d: " format "\n", __FILE__, __LINE__ , ##args )
- #endif
-
- #include <stdlib.h>
- #include <stdfont.h>
- #include <limits.h>
- #include <string.h>
-
- #define countof(A) (sizeof (A) / sizeof ((A)[0]))
-
- FontInformation::FontInformation (HWND hwnd)
- {
- HPS hps = WinGetPS (hwnd);
- HDC hdc = GpiQueryDevice (hps);
-
- // Get out the vertical and horizontal device resolution for later use
- DevQueryCaps (hdc, CAPS_HORIZONTAL_FONT_RES, 1, &xres);
- DevQueryCaps (hdc, CAPS_VERTICAL_FONT_RES, 1, &yres);
-
- // Query the number of fonts involved
- long foobar = 0;
- font_count = GpiQueryFonts (hps, QF_PUBLIC, 0, &foobar, 0, 0);
-
- // Allocate enough room to store all font information
- font_metrics = (FONTMETRICS *) malloc (font_count * sizeof (*font_metrics));
-
- // Fill the newly allocated array with all the font information
- foobar = font_count;
- GpiQueryFonts (hps, QF_PUBLIC, 0, &foobar,
- sizeof (*font_metrics), font_metrics);
-
- WinReleasePS (hps);
-
- int i;
- for (i = 0; i < countof (default_font_set); i++)
- default_font_set[i] = 0;
-
- #ifndef NDEBUG
- for (i = 0; i < font_count; i++)
- {
- FONTMETRICS *fm = &font_metrics[i];
- LOG ("Font #%d", i);
- LOG (" Family: `%s', Face: `%s'", fm->szFamilyname, fm->szFacename);
- LOG (" Point size: %d, xres: %d, yres: %d", fm->sNominalPointSize,
- fm->sXDeviceRes, fm->sYDeviceRes);
- LOG (" Selection: 0x%X, Defn: 0x%X", fm->fsSelection, fm->fsDefn);
- }
- #endif
- }
-
- FontInformation::~FontInformation ()
- {
- if (font_metrics)
- free (font_metrics);
- }
-
-
- // The following condition functions are used to test a fontmetric
- // to see if it matches a desired condition
- struct MatchInfo
- {
- const char *facename;
- int pointsize;
- int xres, yres;
- };
-
- typedef int (*MatchFunction) (const FONTMETRICS *, const MatchInfo *);
-
- static int fm_match (int fontcount, const FONTMETRICS *fm, MatchInfo *mi,
- MatchFunction matchfunction)
- {
- int i;
- for (i = 0; i < fontcount; i++)
- {
- const FONTMETRICS * const metric = &fm[i];
- // Only match fonts with the right facename
- if (strcmp (metric->szFacename, mi->facename))
- continue;
- // See if the match function thinks the font is ok
- if (matchfunction (metric, mi))
- return i;
- }
- return -1;
- }
-
- static int fm_exact_bitmap_font (FONTMETRICS *fm, MatchInfo *mi)
- {
- return
- (!(fm->fsDefn & FM_DEFN_OUTLINE) // Bitmap font
- && fm->sNominalPointSize == mi->pointsize // Right pointsize
- && fm->sXDeviceRes == mi->xres // Right X resolution
- && fm->sYDeviceRes == mi->yres); // Right Y resolution
- }
-
- static int fm_exact_vector_font (const FONTMETRICS *fm, const MatchInfo *mi)
- {
- return
- ((fm->fsDefn & FM_DEFN_OUTLINE) // Vector font
- && fm->sNominalPointSize == mi->pointsize); // Exact point size
- }
-
- static int fm_inexact_vector_font (const FONTMETRICS *fm, const MatchInfo *mi)
- {
- return
- ((fm->fsDefn & FM_DEFN_OUTLINE) // Vector font
- && fm->sMinimumPointSize <= mi->pointsize // Font ok sizewise
- && mi->pointsize <= fm->sMaximumPointSize);
- }
-
- static int fm_poor_vector_font (const FONTMETRICS *fm, const MatchInfo *mi)
- {
- return (fm->fsDefn & FM_DEFN_OUTLINE); // Any vector font
- }
-
- int FontInformation::find_match (const char *fontspec, unsigned *pointsize)
- {
- // Make sure we have a valid argument
- if (fontspec == 0)
- return -1;
-
- // Parse the point size
- char *rest;
- unsigned long ptsize = strtoul (fontspec, &rest, 10);
- if (*rest != '.' || ptsize == ULONG_MAX)
- return -1;
- rest++; // Skip the '.'
- ptsize *= 10;
- if (pointsize)
- *pointsize = ptsize;
-
- // Skip italic and bold specifiers
- const char * const boldspec = "bold.";
- const char * const italicspec = "italic.";
- const int boldspeclen = strlen (boldspec);
- const int italicspeclen = strlen (italicspec);
- do {
- if (!strncmp (rest, boldspec, boldspeclen))
- {
- rest += boldspeclen;
- continue;
- }
- if (!strncmp (rest, italicspec, italicspeclen))
- {
- rest += italicspeclen;
- continue;
- }
- } while (0);
-
- // The rest of the stuff is the face name
- const char * const face_name = rest;
- if (face_name[0] == '\0')
- return -1;
-
- // Then find a match
- MatchInfo matchinfo;
- matchinfo.facename = face_name;
- matchinfo.pointsize = ptsize;
- matchinfo.xres = xres;
- matchinfo.yres = yres;
- MatchFunction matchfunctions[] = {
- fm_exact_bitmap_font,
- fm_exact_vector_font,
- fm_inexact_vector_font,
- fm_poor_vector_font
- };
- int i;
- for (i = 0; i < countof (matchfunctions); i++)
- {
- int match = fm_match (font_count, font_metrics, &matchinfo,
- matchfunctions[i]);
- if (match != -1)
- return match;
- }
- return -1;
- }
-
- int FontInformation::install_font (const char *fontspec)
- {
- unsigned pointsize;
- int fontindex = find_match (fontspec, &pointsize);
- LOG ("Match for `%s' found at index %d", fontspec, fontindex);
- if (fontindex < 0 || font_count <= fontindex)
- return 0;
- int i;
- for (i = 1; i < countof (default_font_set); i++)
- if (default_font_set[i] == 0)
- {
- LOG ("Installing index %d in font slot %d", fontindex, i);
- default_font_set[i] = &font_metrics[fontindex];
- LOG ("FOOBAR #1 is at %p", default_font_set[1]);
- default_font_pointsize[i] = pointsize;
- return i;
- }
- return 0;
- }
-
- void FontInformation::deinstall_font (int fonthandle)
- {
- if (fonthandle < 0 || countof (default_font_set) <= fonthandle)
- return;
- default_font_set[fonthandle] = 0;
- }
-
- void FontInformation::make_fonts_availible (HPS hps)
- {
- int i;
- for (i = 1; i < 256; i++)
- {
- const FONTMETRICS * const fm = default_font_set[i];
- if (fm != 0)
- {
- // Convert the fontmetric into a fattrs
- FATTRS fa;
- memset (&fa, 0, sizeof (fa));
- fa.usRecordLength = sizeof (fa);
- fa.lMatch = fm->lMatch;
- strcpy (fa.szFacename, fm->szFacename);
- fa.idRegistry = fm->idRegistry;
- if ((fm->fsDefn & FM_DEFN_OUTLINE))
- fa.fsType = FATTR_TYPE_KERNING;
- else
- {
- fa.lMaxBaselineExt = fm->lMaxBaselineExt;
- fa.lAveCharWidth = fm->lAveCharWidth;
- }
- // Then create a suitable logical font
- GpiCreateLogFont (hps, 0, i, &fa);
- }
- }
- }
-
- void FontInformation::use_font (HPS hps, int fonthandle)
- {
- if (default_font_set[fonthandle] == 0)
- {
- GpiSetCharSet (hps, 0);
- return;
- }
- GpiSetCharSet (hps, fonthandle);
- // If using a vector font, set up the point size
- if ((default_font_set[fonthandle]->fsDefn & FM_DEFN_OUTLINE))
- {
- SIZEF box;
- box.cx = ((xres * default_font_pointsize[fonthandle]) << 16) / 720;
- box.cy = ((yres * default_font_pointsize[fonthandle]) << 16) / 720;
- GpiSetCharBox (hps, &box);
- }
- }
-
- const FONTMETRICS *FontInformation::get_fontmetrics (int fonthandle)
- {
- return default_font_set[fonthandle];
- }
-
- int FontInformation::get_font_height (int fonthandle)
- {
- const FONTMETRICS *fm = default_font_set[fonthandle];
- if (fm == 0)
- return 0;
- if (fm->fsDefn & FM_DEFN_OUTLINE)
- // Scale the vector font appropriately
- return (yres * default_font_pointsize[fonthandle]) / 720;
- else
- return fm->lMaxBaselineExt;
- }
-
- int FontInformation::get_fonts_height ()
- {
- int height = 0;
- for (int i = 0; i < countof (default_font_set); i++)
- {
- int fontheight = get_font_height (i);
- if (fontheight > height)
- height = fontheight;
- }
- return height;
- }
-
- int FontInformation::get_font_width (int fonthandle)
- {
- const FONTMETRICS *fm = default_font_set[fonthandle];
- if (fm == 0)
- return 0;
- if (fm->fsDefn & FM_DEFN_OUTLINE)
- {
- const unsigned fx_lMaxBaselineExt =
- ((xres * default_font_pointsize[fonthandle]) << 16) / 720;
- const unsigned fx_lAveCharWidth =
- (fx_lMaxBaselineExt * fm->lAveCharWidth) / fm->lMaxBaselineExt;
- return fx_lAveCharWidth >> 16;
- }
- else
- return fm->lAveCharWidth;
- }
-
- int FontInformation::get_fonts_width ()
- {
- int width = 0;
- for (int i = 0; i < countof (default_font_set); i++)
- {
- int fontwidth = get_font_width (i);
- if (fontwidth > width)
- width = fontwidth;
- }
- return width;
- }
-
- int FontInformation::get_font_descender (int fonthandle)
- {
- const FONTMETRICS *fm = default_font_set[fonthandle];
- if (fm == 0)
- return 0;
- if (fm->fsDefn & FM_DEFN_OUTLINE)
- {
- const unsigned fx_lMaxBaselineExt =
- ((yres * default_font_pointsize[fonthandle]) << 16) / 720;
- const unsigned fx_lMaxDescender =
- (fx_lMaxBaselineExt * fm->lMaxDescender) / fm->lMaxBaselineExt;
- return fx_lMaxDescender >> 16;
- }
- else
- return fm->lMaxDescender;
- }
-
- int FontInformation::get_fonts_descender ()
- {
- int descender = 0;
- for (int i = 1; i < countof (default_font_set); i++)
- {
- int fontdescender = get_font_descender (i);
- if (fontdescender > descender)
- descender = fontdescender;
- }
- return descender;
- }
-
- int FontInformation::string_width (HPS hps, int length, const char *text)
- {
- POINTL pts[TXTBOX_COUNT];
- GpiQueryTextBox (hps, length, text, TXTBOX_COUNT, pts);
- return pts[TXTBOX_TOPRIGHT].x;
- }
-
-
- FontInformation *desktop_fontinfo = 0;
-
- void init_desktop_fontinfo ()
- {
- desktop_fontinfo = new FontInformation (HWND_DESKTOP);
- }
-