font_hz_file.c 4.5 KB
Newer Older
B
bernard.xiong 已提交
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
/*
 * Cached HZ font engine
 */
#include <rtgui/dc.h>
#include <rtgui/font.h>
#include <rtgui/tree.h>
#include <rtgui/rtgui_system.h>
#include <dfs_posix.h>

#define HZ_DATA_SIZE    (2 * 16)
#define HZ_CACHE_MAX    64
SPLAY_HEAD(cache_tree, hz_cache);
struct hz_cache
{
    SPLAY_ENTRY(hz_cache) hz_node;

    rt_uint16_t hz_id;
};

struct rtgui_hz_file_font
{
    struct cache_tree cache_root;
    rt_uint16_t cache_size;

    /* font size */
    rt_uint16_t font_size;

    /* file descriptor */
    int fd;

    /* font file name */
    const char* font_fn;
};

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

static void rtgui_hz_file_font_load(struct rtgui_font* font);
static void rtgui_hz_file_font_draw_text(struct rtgui_font* font, struct rtgui_dc* dc, const rt_uint8_t* text, rt_ubase_t len, struct rtgui_rect* rect);
static void rtgui_hz_file_font_get_metrics(struct rtgui_font* font, const rt_uint8_t* text, rtgui_rect_t* rect);
struct rtgui_font_engine rtgui_hz_file_font_engine =
{
	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;
    cache = SPLAY_FIND(cache_tree, &(font->cache_root), &search);
    if (cache != RT_NULL)
    {
        /* find it */
        return (rt_uint8_t*)(cache + 1);
    }

    /* can not find it, load to cache */
    cache = (struct hz_cache*) rtgui_malloc(sizeof(struct hz_cache) + HZ_DATA_SIZE);
    if (cache == RT_NULL) return RT_NULL; /* no memory yet */

    cache->hz_id = hz_id;
    seek = 94 * ((hz_id & 0xff - 0xA0) - 1) + ((hz_id >> 8) - 0xA0);
    seek = seek * HZ_DATA_SIZE;

    /* read hz font data */
    if ((lseek(font->fd, seek, SEEK_SET) < 0) ||
        read(font->fd, (char*)(cache + 1), HZ_DATA_SIZE) !=
        HZ_DATA_SIZE)
    {
        rtgui_free(cache);
        return RT_NULL;
    }

    /* insert to cache */
    SPLAY_INSERT(cache_tree, &(font->cache_root), cache);

    if (font->cache_size > HZ_CACHE_MAX)
    {
        /* remove a cache */
        struct hz_cache* left;
        left = SPLAY_LEFT(font->cache_root.sph_root, hz_node);
        while (SPLAY_LEFT(left, hz_node) != RT_NULL) left = SPLAY_LEFT(left, hz_node);

        /* remove the left node */
        SPLAY_REMOVE(cache_tree, &(font->cache_root), left);
    }

    return (rt_uint8_t*)(cache + 1);
}

static void rtgui_hz_file_font_load(struct rtgui_font* font)
{
    struct rtgui_hz_file_font* hz_file_font = (struct rtgui_hz_file_font*)font;
    RT_ASSERT(hz_file_font != RT_NULL);

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

static void rtgui_hz_file_font_draw_text(struct rtgui_font* font, struct rtgui_dc* dc, const rt_uint8_t* text, rt_ubase_t len, struct rtgui_rect* rect)
{
	rt_base_t h;
	rt_uint8_t* str;
    struct rtgui_hz_file_font* hz_file_font = (struct rtgui_hz_file_font*)font;
    RT_ASSERT(hz_file_font != RT_NULL);

	/* drawing height */
	h = (hz_file_font->font_size + rect->y1 > rect->y2)?
        rect->y2 - rect->y1 : hz_file_font->font_size;

	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 */
		font_ptr = _font_cache_get(hz_file_font, *(rt_uint16_t*)str);

		/* draw word */
		for (i=0; i < h; i ++)
		{
			for (j=0; j < 2; j++)
				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);
					}
				}
		}

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

static void rtgui_hz_file_font_get_metrics(struct rtgui_font* font, const rt_uint8_t* text, rtgui_rect_t* rect)
{
    struct rtgui_hz_file_font* hz_file_font = (struct rtgui_hz_file_font*)font;
    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;
}