summaryrefslogtreecommitdiff
path: root/draw/glyphcache.c
blob: 9828aa2a9400ae7b7ee5e6b91ec95fcf72cca01c (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
#include "fitz.h"

#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
{
	void *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;
}

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

	for (i = 0; i < fz_hashlen(cache->hash); i++)
	{
		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_drophash(cache->hash);
	fz_free(cache);
}

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

	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 - floor(ctm.e)) * 256;
	key.f = (ctm.f - floor(ctm.f)) * 256;

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

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

	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 NULL;
	}

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

	return NULL;
}