📄 selfont.c
字号:
/*
* Copyright (c) 2000 Greg Haerr <greg@censoft.com>
* Copyright (c) 2000 Morten Rolland
*
* Device-independent font selection routines
*/
/*#define NDEBUG*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h> /* toupper*/
#include <string.h>
#include "device.h"
#if (UNIX | DOS_DJGPP)
#define strcmpi strcasecmp
#endif
#if FONTMAPPER
/* entry points*/
int select_font(const PMWLOGFONT plogfont, char *physname);
/*
* The following structure, defines and variables are used to administrate
* a set of fonts that are scanned when a font is requested. The set of
* fonts can be configured with the GdClearFontList and GdAddFont functions.
*/
struct available_font {
MWLOGFONT lf;
char *foundry;
char *family;
char *fontname;
int fontclass, alias;
struct available_font *next;
};
static struct available_font *all_fonts = 0;
/*
* Stupid little function to perform a comparison of two strings,
* returning one of STREQ_EXACT, STREQ_CASE or STREQ_NOMATCH.
*/
#define STREQ_EXACT 0
#define STREQ_CASE 1
#define STREQ_NOMATCH 2
static int streq(const char *a, const char *b)
{
int rc;
for ( rc = STREQ_EXACT; *a != 0; a++, b++ ) {
if ( *a == *b )
continue;
if ( toupper((unsigned char)*a) != toupper((unsigned char)*b) )
return STREQ_NOMATCH;
rc = STREQ_CASE;
}
if ( *b != 0 )
return STREQ_NOMATCH;
return rc;
}
/*
* Decode the "foundry" information into a MWLF_CLASS_ value denoting
* which rendering system should be used to render the font.
*/
static int decode_font_class(const char *class)
{
if ( class == NULL )
return 0;
if ( !strcmp("T1",class) )
return MWLF_CLASS_T1LIB;
if ( !strcmp("FT",class) )
return MWLF_CLASS_FREETYPE;
if ( !strcmp("MWF",class) )
return MWLF_CLASS_BUILTIN;
return 0;
}
/*
* Try to find a font that matches the foundry and font name
* requested.
*/
void test_font_naming(const char *foundry, const char *fontname,
struct available_font *af,
struct available_font **best, int *goodness)
{
int penalty = 0;
if ( foundry != 0 ) {
if ( af->foundry != 0 ) {
switch ( streq(foundry,af->foundry) ) {
case STREQ_EXACT:
break;
case STREQ_CASE:
penalty += 2;
break;
default:
penalty += 8;
break;
}
} else {
penalty += 4;
}
}
switch ( streq(fontname,af->fontname) ) {
case STREQ_EXACT:
break;
case STREQ_CASE:
penalty += 1;
break;
default:
penalty += 16;
break;
}
if ( *goodness < 0 || penalty < *goodness ) {
*best = af;
*goodness = penalty;
}
}
/*
* The 'test_font_goodness' function attempts to find how suitable a font is
* compared to a desired one. The desired font is specified by:
*
* foundry (can be NULL), family and the MWLOGFONT
* structure (can be NULL).
*
* If any fonts are configured, one will always be returned from here,
* but the goodness may be very bad. The goodness (or similarity)
* factor is computed by adding up:
*/
#define GOODNESS_NO_FONTNAME 1000 /* No matching font-name found*/
#define GOODNESS_WEIGHT_DIFF 1 /* 0-900 for weight difference*/
#define GOODNESS_NO_FOUNDRY 100 /* No foundry */
#define GOODNESS_FOUNDRY_UNKNOWN 16 /* Foundry unknown */
#define GOODNESS_CASE_FAMILY 8
#define GOODNESS_CASE_FONTNAME 4
#define GOODNESS_CASE_FOUNDRY 2
#define GOODNESS_EXACT_FAMILY 1 /* Matched font family */
#define GOODNESS_EXACT_FOUNDRY 0 /* Clean match */
#define GOODNESS_EXACT_FONTNAME 0 /* Clean match */
#define GOODNESS_FAMILY_UNKNOWN 3000
#define GOODNESS_NOMATCH_FAMILY 10000
#define GOODNESS_EXACT_FONTFAMILY 0
#define GOODNESS_CASE_FONTFAMILY 32
#define GOODNESS_CLOSE_SLANT 128
#define GOODNESS_BAD_SLANT 256
#define GOODNESS_WRONG_SPACING 2048
#define GOODNESS_WRONG_SERIFSTYLE 1024
#define GOODNESS_WANTED_SMALLCAPS_NOT_AVAILABLE 4096
#define GOODNESS_ONLY_SMALLCAPS_AVAILABLE 8192
static int find_foundry_penalty(const struct available_font *have,
const char *foundry)
{
if ( foundry == 0 )
return 0;
if ( have->foundry == 0 )
return GOODNESS_FOUNDRY_UNKNOWN;
switch ( streq(foundry,have->foundry) ) {
case STREQ_EXACT:
return GOODNESS_EXACT_FOUNDRY;
break;
case STREQ_CASE:
return GOODNESS_CASE_FOUNDRY;
break;
default:
return GOODNESS_NO_FOUNDRY;
break;
}
}
static int find_family_penalty(const struct available_font *have,
const char *family)
{
if ( family == 0 )
return 0;
if ( have->family == 0 )
return GOODNESS_FAMILY_UNKNOWN;
switch ( streq(family,have->family) ) {
case STREQ_EXACT:
return GOODNESS_EXACT_FAMILY;
break;
case STREQ_CASE:
return GOODNESS_CASE_FAMILY;
break;
default:
return GOODNESS_NOMATCH_FAMILY;
break;
}
}
static int find_fontname_penalty(const struct available_font *have,
const char *fontname)
{
switch ( streq(have->fontname,fontname) ) {
case STREQ_EXACT:
return GOODNESS_EXACT_FONTNAME;
break;
case STREQ_CASE:
return GOODNESS_CASE_FONTNAME;
break;
default:
break;
}
/* Test Fontname against font family name */
if ( have->family != 0 ) {
switch ( streq(have->family,fontname) ) {
case STREQ_EXACT:
return GOODNESS_EXACT_FONTFAMILY;
break;
case STREQ_CASE:
return GOODNESS_CASE_FONTFAMILY;
break;
default:
/* No suitable fontname found */
break;
}
}
return GOODNESS_NO_FONTNAME;
}
static int find_weight_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
int weight_diff;
weight_diff = want->lfWeight - have->lfWeight;
if ( weight_diff < 0 )
weight_diff = -weight_diff;
return weight_diff * GOODNESS_WEIGHT_DIFF;
}
static int find_slant_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
/* See if slant is acceptable */
if ( !want->lfItalic && !want->lfRoman && !want->lfOblique ) {
/* Try to default to Romans if not specified */
if ( have->lfItalic || have->lfOblique )
return GOODNESS_CLOSE_SLANT;
return 0;
}
if ( want->lfItalic && have->lfItalic )
return 0;
if ( want->lfRoman && have->lfRoman )
return 0;
if ( want->lfOblique && have->lfOblique )
return 0;
/* No perfect match for the slant, try "closest" one */
if ( want->lfItalic && have->lfOblique )
return GOODNESS_CLOSE_SLANT;
if ( want->lfOblique && have->lfItalic )
return GOODNESS_CLOSE_SLANT;
return GOODNESS_BAD_SLANT;
}
static int find_spacing_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
if ( want->lfProportional && have->lfProportional )
return 0;
if ( want->lfMonospace && have->lfMonospace )
return 0;
if ( want->lfMonospace || want->lfProportional )
return GOODNESS_WRONG_SPACING;
return 0; /* No special desires */
}
static int find_serif_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
if ( !want->lfSerif && !want->lfSansSerif )
return 0;
if ( want->lfSerif && have->lfSerif )
return 0;
if ( want->lfSansSerif && have->lfSansSerif )
return 0;
return GOODNESS_WRONG_SERIFSTYLE;
}
static int find_smallcaps_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
if ( !want->lfSmallCaps && !have->lfSmallCaps )
return 0;
if ( want->lfSmallCaps && have->lfSmallCaps )
return 0;
if ( want->lfSmallCaps )
return GOODNESS_WANTED_SMALLCAPS_NOT_AVAILABLE;
return GOODNESS_ONLY_SMALLCAPS_AVAILABLE;
}
static void test_font_goodness(const char *foundry, const char *family,
const char *fontname, const PMWLOGFONT lf,
struct available_font *af,
struct available_font **best, int *goodness)
{
int penalty = 0;
penalty += find_foundry_penalty(af,foundry);
penalty += find_family_penalty(af,family);
/* Test Fontname, but only if there is no family */
if ( family == 0 )
penalty += find_fontname_penalty(af,fontname);
if ( lf != 0 ) {
/* Check logical font attributes */
penalty += find_weight_penalty(lf,&af->lf);
penalty += find_slant_penalty(lf,&af->lf);
penalty += find_spacing_penalty(lf,&af->lf);
penalty += find_serif_penalty(lf,&af->lf);
penalty += find_smallcaps_penalty(lf,&af->lf);
}
/* See if this font is better than the previous one */
if ( *goodness < 0 || penalty < *goodness ) {
/* Yes, this font is better; change to it */
*best = af;
*goodness = penalty;
}
}
static struct available_font *find_suitable_font(const char *foundry,
const char *fontname,
const PMWLOGFONT plogfont)
{
struct available_font *af, *best;
char *family;
int goodness;
/*
* Try to find a font that matches the name specified as the
* desired font (and foundry if possible). If we find a
* suitable font, we will use the family name when trying to
* find a font that matches the MWLOGFONT attributes. This
* makes it possible to ask for an Italic version of
* "Times Roman" and the expected thing will happen (get the
* font "Times Italic").
*/
goodness = -1;
for ( af = best = all_fonts; af != 0; af = af->next ) {
test_font_naming(foundry,fontname,af,&best,&goodness);
}
family = 0;
if ( goodness != -1 ) {
/* A font with a name that kind of matched was found,
* make a note of its family. If it has no family, we
* can't make any use of the
*/
family = best->family;
}
/*
* Try to find the closest font that matches the font family
* we have established. If no family was found above, all
* fonts will be considered.
*/
goodness = -1;
for ( af = best = all_fonts; af != 0; af = af->next ) {
test_font_goodness(foundry,family,fontname,plogfont,af,
&best,&goodness);
}
return best;
}
int select_font(const PMWLOGFONT plogfont, char *physname)
{
struct available_font *font;
char fndry[128], *foundry;
const char *fontname;
char *tmp;
int t, comma;
int fontclass = 0;
int found_font = 0;
fontname = plogfont->lfFaceName;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -