font_hz_file.c 5.6 KB
Newer Older
B
bernard.xiong 已提交
1 2 3 4 5 6 7
/*
 * Cached HZ font engine
 */
#include <rtgui/dc.h>
#include <rtgui/font.h>
#include <rtgui/tree.h>
#include <rtgui/rtgui_system.h>
B
bernard.xiong@gmail.com 已提交
8

B
bernard.xiong 已提交
9
#ifdef RTGUI_USING_HZ_FILE
B
bernard.xiong 已提交
10 11 12 13 14 15 16
#include <dfs_posix.h>

#define HZ_CACHE_MAX    64

static int _font_cache_compare(struct hz_cache* node1, struct hz_cache* node2);

static void rtgui_hz_file_font_load(struct rtgui_font* font);
17 18
static void rtgui_hz_file_font_draw_text(struct rtgui_font* font, struct rtgui_dc* dc, const char* text, rt_ubase_t len, struct rtgui_rect* rect);
static void rtgui_hz_file_font_get_metrics(struct rtgui_font* font, const char* text, rtgui_rect_t* rect);
19
const struct rtgui_font_engine rtgui_hz_file_font_engine =
B
bernard.xiong 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
{
	RT_NULL,
	rtgui_hz_file_font_load,
	rtgui_hz_file_font_draw_text,
	rtgui_hz_file_font_get_metrics
};

SPLAY_PROTOTYPE(cache_tree, hz_cache, hz_node, _font_cache_compare);
SPLAY_GENERATE (cache_tree, hz_cache, hz_node, _font_cache_compare);

static int _font_cache_compare(struct hz_cache* cache_1, struct hz_cache* cache_2)
{
    if (cache_1->hz_id > cache_2->hz_id) return 1;
    if (cache_1->hz_id < cache_2->hz_id) return -1;

    return 0;
}

static rt_uint8_t* _font_cache_get(struct rtgui_hz_file_font* font, rt_uint16_t hz_id)
{
    rt_uint32_t seek;
    struct hz_cache *cache, search;

    search.hz_id = hz_id;
44 45 46 47 48

	/* enter critical */
	rtgui_enter_critical();

	cache = SPLAY_FIND(cache_tree, &(font->cache_root), &search);
B
bernard.xiong 已提交
49 50
    if (cache != RT_NULL)
    {
51 52 53 54
		/* exit critical */
		rtgui_exit_critical();

        /* found it */
B
bernard.xiong 已提交
55 56 57
        return (rt_uint8_t*)(cache + 1);
    }

58 59 60 61
	/* exit critical */
	rtgui_exit_critical();

	/* can not find it, load to cache */
62
    cache = (struct hz_cache*) rtgui_malloc(sizeof(struct hz_cache) + font->font_data_size);
63 64
    if (cache == RT_NULL)
		return RT_NULL; /* no memory yet */
B
bernard.xiong 已提交
65 66

    cache->hz_id = hz_id;
67 68
    seek = 94 * (((hz_id & 0xff) - 0xA0) - 1) + ((hz_id >> 8) - 0xA0) - 1;
    seek *= font->font_data_size;
B
bernard.xiong 已提交
69 70 71

    /* read hz font data */
    if ((lseek(font->fd, seek, SEEK_SET) < 0) ||
72 73
        read(font->fd, (char*)(cache + 1), font->font_data_size) !=
        font->font_data_size)
B
bernard.xiong 已提交
74 75 76 77 78
    {
        rtgui_free(cache);
        return RT_NULL;
    }

79 80 81 82
	/* enter critical */
	rtgui_enter_critical();

	/* insert to cache */
B
bernard.xiong 已提交
83
    SPLAY_INSERT(cache_tree, &(font->cache_root), cache);
84
	font->cache_size ++;
B
bernard.xiong 已提交
85 86 87 88 89

    if (font->cache_size > HZ_CACHE_MAX)
    {
        /* remove a cache */
        struct hz_cache* left;
B
bernard.xiong 已提交
90
        left = font->cache_root.sph_root;
B
bernard.xiong 已提交
91 92 93
        while (SPLAY_LEFT(left, hz_node) != RT_NULL) left = SPLAY_LEFT(left, hz_node);

        /* remove the left node */
B
bernard.xiong 已提交
94
        SPLAY_REMOVE(cache_tree, &(font->cache_root), left);
95
		rtgui_free(left);
96
		font->cache_size --;
B
bernard.xiong 已提交
97 98
    }

99 100 101
	/* exit critical */
	rtgui_exit_critical();

B
bernard.xiong 已提交
102 103 104 105 106
    return (rt_uint8_t*)(cache + 1);
}

static void rtgui_hz_file_font_load(struct rtgui_font* font)
{
107
    struct rtgui_hz_file_font* hz_file_font = (struct rtgui_hz_file_font*)font->data;
B
bernard.xiong 已提交
108 109 110 111 112
    RT_ASSERT(hz_file_font != RT_NULL);

    hz_file_font->fd = open(hz_file_font->font_fn, O_RDONLY, 0);
}

B
bernard.xiong@gmail.com 已提交
113
static void _rtgui_hz_file_font_draw_text(struct rtgui_hz_file_font* hz_file_font, struct rtgui_dc* dc, const char* text, rt_ubase_t len, struct rtgui_rect* rect)
B
bernard.xiong 已提交
114 115
{
	rt_uint8_t* str;
116 117 118 119 120 121 122
	rtgui_color_t bc;
	rt_uint16_t style;
	register rt_base_t h, word_bytes;

	/* get text style */
	style = rtgui_dc_get_gc(dc)->textstyle;
	bc = rtgui_dc_get_gc(dc)->background;
B
bernard.xiong 已提交
123 124 125 126

	/* drawing height */
	h = (hz_file_font->font_size + rect->y1 > rect->y2)?
        rect->y2 - rect->y1 : hz_file_font->font_size;
127
	word_bytes = (hz_file_font->font_size + 7) / 8;
B
bernard.xiong 已提交
128 129 130 131 132 133 134 135 136

	str = (rt_uint8_t*)text;

	while (len > 0 && rect->x1 < rect->x2)
	{
		const rt_uint8_t* font_ptr;
		register rt_base_t i, j, k;

		/* get font pixel data */
137
		font_ptr = _font_cache_get(hz_file_font, *str | (*(str+1) << 8));
B
bernard.xiong 已提交
138 139 140 141

		/* draw word */
		for (i=0; i < h; i ++)
		{
142
			for (j=0; j < word_bytes; j++)
B
bernard.xiong 已提交
143 144 145 146 147 148 149
				for (k=0; k < 8; k++)
				{
					if ( ((font_ptr[i*2 + j] >> (7-k)) & 0x01) != 0 &&
						(rect->x1 + 8 * j + k < rect->x2))
					{
						rtgui_dc_draw_point(dc, rect->x1 + 8*j + k, rect->y1 + i);
					}
150 151 152 153
					else if (style & RTGUI_TEXTSTYLE_DRAW_BACKGROUND)
					{
						rtgui_dc_draw_color_point(dc, rect->x1 + 8*j + k, rect->y1 + i, bc);
					}
B
bernard.xiong 已提交
154 155 156 157 158 159 160 161 162 163
				}
		}

		/* move x to next character */
		rect->x1 += hz_file_font->font_size;
		str += 2;
		len -= 2;
	}
}

164 165 166 167
static void rtgui_hz_file_font_draw_text(struct rtgui_font* font, struct rtgui_dc* dc, const char* text, rt_ubase_t length, struct rtgui_rect* rect)
{
	rt_uint32_t len;
	struct rtgui_font *efont;
B
bernard.xiong@gmail.com 已提交
168
	struct rtgui_hz_file_font* hz_file_font = (struct rtgui_hz_file_font*)font->data;
169 170

	RT_ASSERT(dc != RT_NULL);
B
bernard.xiong@gmail.com 已提交
171
	RT_ASSERT(hz_file_font != RT_NULL);
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

	/* get English font */
	efont = rtgui_font_refer("asc", hz_file_font->font_size);
	if (efont == RT_NULL) efont = rtgui_font_default(); /* use system default font */

	while (length > 0)
	{
		len = 0;
		while (((rt_uint8_t)*(text + len)) < 0x80 && *(text + len)) len ++;
		/* draw text with English font */
		if (len > 0)
		{
			rtgui_font_draw(efont, dc, text, len, rect);

			text += len;
			length -= len;
		}

		len = 0;
		while (((rt_uint8_t)*(text + len)) >= 0x80) len ++;
		if (len > 0)
		{
			_rtgui_hz_file_font_draw_text(hz_file_font, dc, text, len, rect);

			text += len;
			length -= len;
		}
	}

	rtgui_font_derefer(efont);
B
bernard.xiong@gmail.com 已提交
202 203
}

204
static void rtgui_hz_file_font_get_metrics(struct rtgui_font* font, const char* text, rtgui_rect_t* rect)
B
bernard.xiong 已提交
205
{
206
    struct rtgui_hz_file_font* hz_file_font = (struct rtgui_hz_file_font*)font->data;
B
bernard.xiong 已提交
207 208 209 210 211 212 213
    RT_ASSERT(hz_file_font != RT_NULL);

	/* set metrics rect */
	rect->x1 = rect->y1 = 0;
	rect->x2 = (rt_int16_t)(hz_file_font->font_size/2 * rt_strlen((const char*)text));
	rect->y2 = hz_file_font->font_size;
}
B
bernard.xiong 已提交
214
#endif