📄 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 2static 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 8192static 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 + -