summaryrefslogtreecommitdiff
path: root/fscalc.cpp
blob: 6842a6524b0986dfa587341e456f9dfeb28f5f95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <stdexcept>
#include "fscalc.h"

Font::Font(std::string s, int slant, int weight) {
	FcPattern *tmp1, *tmp2, *final;
	FcResult res;
	FcChar8 *filename;
	int fontindex;

	if(!(fc = FcInitLoadConfigAndFonts()))
		throw(std::runtime_error("failed to initialize fontconfig"));

	if(FT_Init_FreeType(&library))
		throw(std::runtime_error("failed to initialize freetype"));

	aux = FcPatternCreate();

	tmp1 = FcPatternBuild(NULL,
		FC_FAMILY, FcTypeString, s.c_str(),
		FC_SLANT, FcTypeInteger, slant,
		FC_WEIGHT, FcTypeInteger, weight ? 300 : 100,
		NULL);
	if(!tmp1)
		throw(std::runtime_error("failed to load font"));

	tmp2 = FcFontRenderPrepare(fc, tmp1, aux);
	FcPatternDestroy(tmp1);
	final = FcFontMatch(fc, tmp2, &res);
	FcPatternDestroy(tmp2);
	if(!final)
		throw(std::runtime_error("failed to load font"));

	if(FcPatternGetString(final, FC_FILE, 0, &filename) != FcResultMatch || FcPatternGetInteger(final, FC_INDEX, 0, &fontindex) != FcResultMatch) {
		FcPatternDestroy(final);
		throw(std::runtime_error("failed to locate font"));
	}

	if(FT_New_Face(library, (char*)filename, fontindex, &face)) {
		FcPatternDestroy(final);
		throw(std::runtime_error("failed to create new face"));
	}

	FcPatternDestroy(final);
	FcPatternDestroy(aux);
// 	FcFini();
}

Font::~Font() {
	FT_Done_Face(face);
	FT_Done_FreeType(library);
}

void Font::set_font_size(int size) {
	FT_Size_RequestRec req;
	TT_OS2 *os2;
	TT_HoriHeader *hori;
	float scale = 1.0;

	FT_Size_Metrics *m = &face->size->metrics;

	os2 = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
	hori = (TT_HoriHeader*)FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
	if(os2 && hori) {
		int horisum = hori->Ascender - hori->Descender;
		unsigned int winsum = os2->usWinAscent + os2->usWinDescent;
		scale = (float)horisum / (float)winsum;
	}

	req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
	req.width = 0;
	req.height = (FT_F26Dot6)(size * 64 * scale);
	req.horiResolution = 0;
	req.vertResolution = 0;
	FT_Request_Size(face, &req);
}

double Font::get_kerning(FT_UInt left, FT_UInt right) {
	if(FT_HAS_KERNING(face)) {
		FT_Vector d;
		FT_Get_Kerning(face, left, right, 0, &d);
		return (double)d.x / 64.0;
	} else return 0;
}

unsigned int Font::get_text_width(std::string s) {
	FT_UInt prev = 0;
	bool kerning = FT_HAS_KERNING(face);
	double width = 0;
	for(std::string::iterator c = s.begin(); c < s.end(); c++) {
		int i = FT_Get_Char_Index(face, *c);
		if(kerning && prev && i)
			width += get_kerning(prev, i);
		if(FT_Load_Char(face, *c, 0))
			throw(std::runtime_error("failed to load char"));
		width += (double)face->glyph->advance.x / 64.0;
	}
	return int(width);
}

unsigned int Font::get_line_height() {
	return face->bbox.yMax - face->bbox.yMin;
}