⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 selfont.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -