glyphcache.c

来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· C语言 代码 · 共 394 行

C
394
字号
#include "fitz-base.h"#include "fitz-world.h"#include "fitz-draw.h"typedef struct fz_hash_s fz_hash;typedef struct fz_key_s fz_key;typedef struct fz_val_s fz_val;struct fz_glyphcache_s{	int slots;	int size;	fz_hash *hash;	fz_val *lru;	unsigned char *buffer;	int load;	int used;};struct fz_key_s{	void *fid;	int a, b;	int c, d;	unsigned short cid;	unsigned char e, f;};struct fz_hash_s{	fz_key key;	fz_val *val;};struct fz_val_s{	fz_hash *ent;	unsigned char *samples;	short w, h, x, y;	int uses;};static unsigned int hashkey(fz_key *key){	unsigned char *s = (unsigned char*)key;	unsigned int hash = 0;	unsigned int i;	for (i = 0; i < sizeof(fz_key); i++)	{		hash += s[i];		hash += (hash << 10);		hash ^= (hash >> 6);	}	hash += (hash << 3);	hash ^= (hash >> 11);	hash += (hash << 15);	return hash;}fz_error *fz_newglyphcache(fz_glyphcache **arenap, int slots, int size){	fz_glyphcache *arena;	arena = *arenap = fz_malloc(sizeof(fz_glyphcache));	if (!arena)		return fz_outofmem;	arena->slots = slots;	arena->size = size;	arena->hash = nil;	arena->lru = nil;	arena->buffer = nil;	arena->hash = fz_malloc(sizeof(fz_hash) * slots);	if (!arena->hash)		goto cleanup;	arena->lru = fz_malloc(sizeof(fz_val) * slots);	if (!arena->lru)		goto cleanup;	arena->buffer = fz_malloc(size);	if (!arena->buffer)		goto cleanup;	memset(arena->hash, 0, sizeof(fz_hash) * slots);	memset(arena->lru, 0, sizeof(fz_val) * slots);	memset(arena->buffer, 0, size);	arena->load = 0;	arena->used = 0;	return fz_okay;cleanup:	fz_free(arena->hash);	fz_free(arena->lru);	fz_free(arena->buffer);	fz_free(arena);	return fz_outofmem;}voidfz_dropglyphcache(fz_glyphcache *arena){	fz_free(arena->hash);	fz_free(arena->lru);	fz_free(arena->buffer);	fz_free(arena);}static int hokay = 0;static int hcoll = 0;static int hdist = 0;static int coos = 0;static int covf = 0;static int ghits = 0;static int gmisses = 0;static fz_val *hashfind(fz_glyphcache *arena, fz_key *key){	fz_hash *tab = arena->hash;	int pos = hashkey(key) % arena->slots;	while (1)	{		if (!tab[pos].val)			return nil;		if (memcmp(key, &tab[pos].key, sizeof (fz_key)) == 0)			return tab[pos].val;		pos = pos + 1;		if (pos == arena->slots)			pos = 0;	}}static voidhashinsert(fz_glyphcache *arena, fz_key *key, fz_val *val){	fz_hash *tab = arena->hash;	int pos = hashkey(key) % arena->slots;int didcoll = 0;	while (1)	{		if (!tab[pos].val)		{			tab[pos].key = *key;			tab[pos].val = val;			tab[pos].val->ent = &tab[pos];if (didcoll) hcoll ++; else hokay ++; hdist += didcoll;			return;		}		pos = pos + 1;		if (pos == arena->slots)			pos = 0;didcoll ++;	}}/*static voidhashremove(fz_glyphcache *arena, fz_key *key){	fz_hash *tab = arena->hash;	unsigned int pos = hashkey(key) % arena->slots;	unsigned int hole;	unsigned int look;	unsigned int code;	while (1)	{		if (!tab[pos].val)			return; // boo hoo! tried to remove non-existant key		if (memcmp(key, &tab[pos].key, sizeof (fz_key)) == 0)		{			tab[pos].val = nil;			hole = pos;			look = hole + 1;			if (look == arena->slots)				look = 0;			while (tab[look].val)			{				code = (hashkey(&tab[look].key) % arena->slots);				if ((code <= hole && hole < look) ||					(look < code && code <= hole) ||					(hole < look && look < code))				{					tab[hole] = tab[look];					tab[hole].val->ent = &tab[hole];					tab[look].val = nil;					hole = look;				}				look = look + 1;				if (look == arena->slots)					look = 0;			}			return;		}		pos = pos + 1;		if (pos == arena->slots)			pos = 0;	}}*/voidfz_debugglyphcache(fz_glyphcache *arena){	printf("cache load %d / %d (%d / %d bytes)\n",		arena->load, arena->slots, arena->used, arena->size);	printf("no-colliders: %d colliders: %d\n", hokay, hcoll);	printf("avg dist: %d / %d: %g\n", hdist, hcoll, (double)hdist / hcoll);	printf("out-of-space evicts: %d\n", coos);	printf("out-of-hash evicts: %d\n", covf);	printf("hits = %d misses = %d ratio = %g\n", ghits, gmisses, (float)ghits / (ghits + gmisses));/*	int i;	for (i = 0; i < arena->slots; i++)	{		if (!arena->hash[i].val)			printf("glyph % 4d: empty\n", i);		else {			fz_key *k = &arena->hash[i].key;			fz_val *b = arena->hash[i].val;			printf("glyph % 4d: %p %d [%g %g %g %g + %d %d] "					"-> [%dx%d %d,%d]\n", i,				k->fid, k->cid,				k->a / 65536.0,				k->b / 65536.0,				k->c / 65536.0,				k->d / 65536.0,				k->e, k->f,				b->w, b->h, b->x, b->y);		}	}	for (i = 0; i < arena->load; i++)		printf("lru %04d: glyph %d (%d)\n", i,			arena->lru[i].ent - arena->hash, arena->lru[i].uses);*/}static voidbubble(fz_glyphcache *arena, int i){	fz_val tmp;	if (i == 0 || arena->load < 2)		return;	tmp = arena->lru[i - 1];	arena->lru[i - 1] = arena->lru[i];	arena->lru[i] = tmp;	arena->lru[i - 1].ent->val = &arena->lru[i - 1];	arena->lru[i].ent->val = &arena->lru[i];}/*static voidevictlast(fz_glyphcache *arena){	fz_val *lru = arena->lru;	unsigned char *s, *e;	int i, k;	fz_key key;	if (arena->load == 0)		return;	k = arena->load - 1;	s = lru[k].samples;	e = s + lru[k].w * lru[k].h;	// pack buffer to fill hole	memmove(s, e, arena->buffer + arena->used - e);	memset(arena->buffer + arena->used - (e - s), 0, e - s);	arena->used -= e - s;	// update lru pointers	for (i = 0; i < k; i++)	// XXX this is DOG slow! XXX		if (lru[i].samples >= e)			lru[i].samples -= e - s;	// remove hash entry	key = lru[k].ent->key;	hashremove(arena, &key);	arena->load --;}*/static voidevictall(fz_glyphcache *arena){	memset(arena->hash, 0, sizeof(fz_hash) * arena->slots);	memset(arena->lru, 0, sizeof(fz_val) * arena->slots);	memset(arena->buffer, 0, arena->size);	arena->load = 0;	arena->used = 0;}fz_error *fz_renderglyph(fz_glyphcache *arena, fz_glyph *glyph, fz_font *font, int cid, fz_matrix ctm){	fz_error *error;	fz_key key;	fz_val *val;	int size;	key.fid = 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 - fz_floor(ctm.e)) * 256;	key.f = (ctm.f - fz_floor(ctm.f)) * 256;	val = hashfind(arena, &key);	if (val)	{		val->uses ++;		glyph->w = val->w;		glyph->h = val->h;		glyph->x = val->x;		glyph->y = val->y;		glyph->samples = val->samples;		bubble(arena, val - arena->lru);		ghits++;		return fz_okay;	}	gmisses++;	ctm.e = fz_floor(ctm.e) + key.e / 256.0;	ctm.f = fz_floor(ctm.f) + key.f / 256.0;	error = font->render(glyph, font, cid, ctm);	if (error)		return error;	size = glyph->w * glyph->h;	if (size > arena->size / 6)		return fz_okay;	while (arena->load > arena->slots * 75 / 100)	{		covf ++;		evictall(arena);	}	while (arena->used + size >= arena->size)	{		coos ++;		evictall(arena);	}	val = &arena->lru[arena->load++];	val->uses = 0;	val->w = glyph->w;	val->h = glyph->h;	val->x = glyph->x;	val->y = glyph->y;	val->samples = arena->buffer + arena->used;	arena->used += size;	memcpy(val->samples, glyph->samples, glyph->w * glyph->h);	glyph->samples = val->samples;	hashinsert(arena, &key, val);	return fz_okay;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?