summaryrefslogtreecommitdiff
path: root/draw/draw_glyph.c
blob: 15bb7cae029de815d037fbf34771631d7476ab2f (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "fitz.h"

#define MAXFONTSIZE 1000
#define MAXGLYPHSIZE 256
#define MAXCACHESIZE (1024*1024)

typedef struct fz_glyphkey_s fz_glyphkey;

struct fz_glyphcache_s
{
	fz_hashtable *hash;
	int total;
};

struct fz_glyphkey_s
{
	fz_font *font;
	int a, b;
	int c, d;
	unsigned short cid;
	unsigned char e, f;
};

fz_glyphcache *
fz_newglyphcache(void)
{
	fz_glyphcache *cache;

	cache = fz_malloc(sizeof(fz_glyphcache));
	cache->hash = fz_newhash(509, sizeof(fz_glyphkey));
	cache->total = 0;

	return cache;
}

static void
fz_evictglyphcache(fz_glyphcache *cache)
{
	fz_glyphkey *key;
	fz_pixmap *pixmap;
	int i;

	for (i = 0; i < fz_hashlen(cache->hash); i++)
	{
		key = fz_hashgetkey(cache->hash, i);
		if (key->font)
			fz_dropfont(key->font);
		pixmap = fz_hashgetval(cache->hash, i);
		if (pixmap)
			fz_droppixmap(pixmap);
	}

	cache->total = 0;

	fz_emptyhash(cache->hash);
}

void
fz_freeglyphcache(fz_glyphcache *cache)
{
	fz_evictglyphcache(cache);
	fz_freehash(cache->hash);
	fz_free(cache);
}

fz_pixmap *
fz_renderstrokedglyph(fz_glyphcache *cache, fz_font *font, int cid, fz_matrix trm, fz_matrix ctm, fz_strokestate *stroke)
{
	if (font->ftface)
		return fz_renderftstrokedglyph(font, cid, trm, ctm, stroke);
	return fz_renderglyph(cache, font, cid, trm);
}

fz_pixmap *
fz_renderglyph(fz_glyphcache *cache, fz_font *font, int cid, fz_matrix ctm)
{
	fz_glyphkey key;
	fz_pixmap *val;
	float size = fz_matrixexpansion(ctm);

	if (size > MAXFONTSIZE)
	{
		/* TODO: this case should be handled by rendering glyph as a path fill */
		fz_warn("font size too large (%g), not rendering glyph", size);
		return nil;
	}

	memset(&key, 0, sizeof key);
	key.font = font;
	key.cid = cid;
	key.a = ctm.a * 65536;
	key.b = ctm.b * 65536;
	key.c = ctm.c * 65536;
	key.d = ctm.d * 65536;
	key.e = (ctm.e - floorf(ctm.e)) * 256;
	key.f = (ctm.f - floorf(ctm.f)) * 256;

	val = fz_hashfind(cache->hash, &key);
	if (val)
		return fz_keeppixmap(val);

	ctm.e = floorf(ctm.e) + key.e / 256.0f;
	ctm.f = floorf(ctm.f) + key.f / 256.0f;

	if (font->ftface)
	{
		val = fz_renderftglyph(font, cid, ctm);
	}
	else if (font->t3procs)
	{
		val = fz_rendert3glyph(font, cid, ctm);
	}
	else
	{
		fz_warn("assert: uninitialized font structure");
		return nil;
	}

	if (val)
	{
		if (val->w < MAXGLYPHSIZE && val->h < MAXGLYPHSIZE)
		{
			if (cache->total + val->w * val->h > MAXCACHESIZE)
				fz_evictglyphcache(cache);
			fz_keepfont(key.font);
			fz_hashinsert(cache->hash, &key, val);
			cache->total += val->w * val->h;
			return fz_keeppixmap(val);
		}
		return val;
	}

	return nil;
}