PageRenderTime 1666ms CodeModel.GetById 704ms app.highlight 214ms RepoModel.GetById 742ms app.codeStats 0ms

/src/canvas/default/fontdata.c

http://ftk.googlecode.com/
C | 533 lines | 419 code | 85 blank | 29 comment | 85 complexity | ceab92657695a632a147da999353c889 MD5 | raw file
  1/*
  2 * File: fontdata.c
  3 * Author:  Li XianJing <xianjimli@hotmail.com>
  4 * Brief:   functions to operate font data. 
  5 *
  6 * Copyright (c) 2009 - 2010  Li XianJing <xianjimli@hotmail.com>
  7 *
  8 * Licensed under the Academic Free License version 2.1
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License as published by
 12 * the Free Software Foundation; either version 2 of the License, or
 13 * (at your option) any later version.
 14 *
 15 * This program is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 * GNU General Public License for more details.
 19 *
 20 * You should have received a copy of the GNU General Public License
 21 * along with this program; if not, write to the Free Software
 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 23 */
 24
 25/*
 26 * History:
 27 * ================================================================
 28 * 2009-09-11 Li XianJing <xianjimli@hotmail.com> created
 29 *
 30 */
 31#include "fontdata.h"
 32
 33#ifdef WITHOUT_FTK 
 34#define FTK_ALLOC malloc
 35#define FTK_FREE free
 36#define FTK_ZALLOC(s) calloc(1, s)
 37#define FTK_REALLOC realloc
 38#else
 39#include "ftk_log.h"
 40#include "ftk_allocator.h"
 41#endif
 42
 43#define FONT_VERSION 0x00000101 /*1.01*/
 44
 45typedef struct _FontDataHeader
 46{
 47	unsigned int   version;
 48	unsigned int   char_nr;
 49	unsigned char  width;
 50	unsigned char  height;
 51	unsigned short encoding;
 52	unsigned int   unused;
 53	char author[64];
 54	char family[32];
 55	char style[32];
 56}FontDataHeader;
 57
 58typedef struct _FGlyph
 59{
 60	signed char x;
 61	signed char y;
 62	unsigned char w;
 63	unsigned char h;
 64	unsigned short code;
 65	unsigned short unused;
 66	unsigned offset;
 67}FGlyph;
 68
 69struct _FontData
 70{
 71	FontDataHeader header;
 72
 73	FGlyph* glyphs;
 74	unsigned data_size;
 75	unsigned data_buffer_size;
 76	unsigned char* data;
 77
 78	void* org_data;
 79	int   new_created;
 80
 81	char file_name[260];
 82	void* current_glyph_data;
 83	unsigned current_glyph_data_size;
 84};
 85
 86static Ret font_data_read_glyph(FontData* thiz, unsigned offset, unsigned size, Glyph* glyph);
 87
 88FontData* font_data_create(int char_nr, Encoding encoding)
 89{
 90	FontData* thiz = (FontData*)FTK_ZALLOC(sizeof(FontData));
 91
 92	if(thiz != NULL)
 93	{
 94		thiz->header.version  = FONT_VERSION;
 95		thiz->header.char_nr  = char_nr;
 96		thiz->header.encoding = encoding;
 97		
 98		if(char_nr > 0)
 99		{
100			thiz->new_created = 1;
101			thiz->glyphs = (FGlyph*)FTK_ZALLOC(char_nr * sizeof(FGlyph));
102		}
103	}
104
105	return thiz;
106}
107
108FontData* font_data_load(char* data, unsigned length)
109{
110	FontData* thiz = font_data_create(0, 0);
111
112	return_val_if_fail(data != NULL && length > sizeof(FontDataHeader), NULL);
113
114	if(thiz != NULL)
115	{
116		int glyph_size = 0;
117		thiz->header = *(FontDataHeader*)data;
118		glyph_size = thiz->header.char_nr * sizeof(FGlyph);
119
120		thiz->glyphs = (FGlyph*)(data + sizeof(FontDataHeader));
121		thiz->data = (unsigned char*)(data + sizeof(FontDataHeader) + glyph_size);
122		thiz->data_size = length - ((char*)thiz->data - data);
123		thiz->data_buffer_size = thiz->data_size;
124		thiz->new_created = 0;
125		thiz->org_data = data;
126	}
127
128	return thiz;
129}
130
131#ifdef WITHOUT_FTK
132#include <unistd.h>
133#include <sys/types.h>
134#include <sys/stat.h>
135char* read_file(const char* file_name, int* length)
136{
137	struct stat st = {0};
138	if(stat(file_name, &st))
139	{
140		return NULL;
141	}
142	else
143	{
144		char* buffer = malloc(st.st_size + 1);
145		FILE* fp = fopen(file_name, "rb");
146		fread(buffer, 1, st.st_size, fp);
147		fclose(fp);
148		buffer[st.st_size] = '\0';
149		*length = st.st_size;
150
151		return buffer;
152	}
153}
154
155FontData* font_data_load_file(const char* file_name)
156{
157	int length = 0;
158	char* buffer = read_file(file_name, &length);
159	
160	return font_data_load(buffer, length);
161}
162
163static Ret font_data_read_glyph(FontData* thiz, unsigned offset, unsigned size, Glyph* glyph)
164{
165
166	return RET_FAIL;
167}
168#else
169#include "ftk_file_system.h"
170
171FontData* font_data_load_file(const char* file_name)
172{
173	FontData* thiz = NULL;
174	return_val_if_fail(file_name != NULL, NULL);
175
176	if((thiz = font_data_create(0, 0)) != NULL)
177	{
178		FtkFsHandle fp = ftk_file_open(file_name, "rb");
179		if(fp != NULL)
180		{
181			int ret = 0;
182			unsigned glyphs_size = 0;
183			ret = ftk_file_read(fp, &thiz->header, sizeof(thiz->header));
184			assert(ret == sizeof(thiz->header));
185			glyphs_size = thiz->header.char_nr * sizeof(FGlyph);
186			thiz->glyphs = (FGlyph*)FTK_ZALLOC(glyphs_size);
187			assert(thiz->glyphs != NULL);
188			ftk_file_read(fp, thiz->glyphs, glyphs_size);
189			thiz->data = NULL;
190			thiz->data_size = 0;
191			thiz->new_created = 0;
192			thiz->org_data = NULL;
193			ftk_file_close(fp);
194			ftk_strncpy(thiz->file_name, file_name, sizeof(thiz->file_name)-1);
195		}
196		else
197		{
198			FTK_FREE(thiz);
199		}
200	}
201
202	return thiz;
203}
204
205static Ret font_data_read_glyph(FontData* thiz, unsigned offset, unsigned size, Glyph* glyph)
206{
207	int ret = 0;
208	FtkFsHandle fp = ftk_file_open(thiz->file_name, "rb");
209	unsigned skip = sizeof(thiz->header) + thiz->header.char_nr * sizeof(FGlyph) + offset;
210	return_val_if_fail(fp != NULL && glyph != NULL, RET_FAIL);
211
212	ret = ftk_file_seek(fp, skip);
213	assert(ret == 0);
214	
215	if(thiz->current_glyph_data_size < size)
216	{
217		FTK_FREE(thiz->current_glyph_data);
218		thiz->current_glyph_data = FTK_ALLOC(size * 2);
219		thiz->current_glyph_data_size = size * 2;
220	}
221
222	ret = ftk_file_read(fp, thiz->current_glyph_data, size);
223	ftk_logd("%s: offset=%d size=%d ret=%d\n", __func__, offset, size, ret);
224	ftk_file_close(fp);
225	assert(ret == size);
226	glyph->data = thiz->current_glyph_data;
227
228	return RET_OK;
229}
230#endif
231
232Ret font_data_add_glyph(FontData* thiz, Glyph* glyph)
233{
234	unsigned i = 0;
235	return_val_if_fail(thiz != NULL && glyph != NULL && thiz->new_created, RET_FAIL);
236	
237	for(i = 0; i < thiz->header.char_nr; i++)
238	{
239		if(thiz->glyphs[i].code == glyph->code)
240		{
241			return RET_FOUND;
242		}
243
244		if(thiz->glyphs[i].code > glyph->code || thiz->glyphs[i].code == 0)
245		{
246			unsigned size = glyph->w * glyph->h;
247			if(thiz->glyphs[i].code > glyph->code)
248			{
249				unsigned k = 0;
250				for(k = thiz->header.char_nr - 1; k > i; k--)
251				{
252					thiz->glyphs[k] = thiz->glyphs[k-1];
253				}
254			}
255
256			if((thiz->data_size + size) >= thiz->data_buffer_size)
257			{
258				unsigned data_buffer_size = thiz->data_buffer_size + (thiz->data_buffer_size >> 1) + (size << 4);
259				unsigned char* data = (unsigned char*)FTK_REALLOC(thiz->data, data_buffer_size);
260				if(data != NULL)
261				{
262					thiz->data = data;
263					thiz->data_buffer_size = data_buffer_size;
264				}
265			}
266
267			if((thiz->data_size + size) < thiz->data_buffer_size)
268			{
269				memcpy(thiz->data + thiz->data_size, glyph->data, size);
270				thiz->glyphs[i].offset = thiz->data_size;
271                thiz->glyphs[i].x = glyph->x;
272                thiz->glyphs[i].y = glyph->y;
273                thiz->glyphs[i].w = glyph->w;
274                thiz->glyphs[i].h = glyph->h;
275                thiz->glyphs[i].code = glyph->code;
276                thiz->glyphs[i].unused = glyph->unused;
277				thiz->data_size += size;
278			}
279            else
280                return RET_OUT_OF_SPACE;
281			return RET_OK;
282		}
283	}
284
285	return RET_FAIL;
286}
287
288Ret font_data_get_glyph(FontData* thiz, unsigned short code, Glyph* glyph)
289{
290    int low    = 0;
291    int mid    = 0;
292    int high   = 0;
293    int result = 0;
294
295    return_val_if_fail(thiz != NULL && glyph != NULL, RET_FAIL);
296
297    high = thiz->header.char_nr;
298    while(low <= high)
299    {
300        mid  = low + ((high - low) >> 1);
301        result = thiz->glyphs[mid].code - code;
302
303        if(result == 0)
304        {
305            glyph->x = thiz->glyphs[mid].x;
306            glyph->y = thiz->glyphs[mid].y;
307            glyph->w = thiz->glyphs[mid].w;
308            glyph->h = thiz->glyphs[mid].h;
309            glyph->code = thiz->glyphs[mid].code;
310            glyph->unused = thiz->glyphs[mid].unused;
311			if(thiz->data != NULL)
312			{
313				glyph->data = (unsigned char*)(thiz->data + (int)(thiz->glyphs[mid].offset));
314			}
315			else
316			{
317				font_data_read_glyph(thiz, thiz->glyphs[mid].offset, glyph->w * glyph->h, glyph);
318			}
319            return RET_OK;
320        }
321        else if(result < 0)
322        {
323            low = mid + 1;
324        }
325        else
326        {
327            high = mid - 1;
328        }
329    }
330
331    return RET_FAIL;
332}
333
334int  font_data_get_version(FontData* thiz)
335{
336	return_val_if_fail(thiz != NULL, 0);
337
338	return thiz->header.version;
339}
340
341int  font_data_get_width(FontData* thiz)
342{
343	return_val_if_fail(thiz != NULL, 0);
344
345	return thiz->header.width;
346}
347
348int  font_data_get_height(FontData* thiz)
349{
350	return_val_if_fail(thiz != NULL, 0);
351
352	return thiz->header.height;
353}
354
355const char* font_data_get_author(FontData* thiz)
356{
357	return_val_if_fail(thiz != NULL, NULL);
358
359	return thiz->header.author;
360}
361
362const char* font_data_get_family(FontData* thiz)
363{
364	return_val_if_fail(thiz != NULL, NULL);
365
366	return thiz->header.family;
367}
368
369const char* font_data_get_style(FontData* thiz)
370{
371	return_val_if_fail(thiz != NULL, NULL);
372
373	return thiz->header.style;
374}
375
376void font_data_set_size(FontData* thiz, int width, int height)
377{
378	return_if_fail(thiz != NULL);
379
380	thiz->header.width  = width;
381	thiz->header.height = height;
382	
383	return;
384}
385
386void font_data_set_author(FontData* thiz, const char* author)
387{
388	return_if_fail(thiz != NULL);
389	
390	ftk_strncpy(thiz->header.author, author, sizeof(thiz->header.author));
391
392	return;
393}
394
395void font_data_set_family(FontData* thiz, const char* family)
396{
397	return_if_fail(thiz != NULL);
398	
399	ftk_strncpy(thiz->header.family, family, sizeof(thiz->header.family));
400
401	return;
402}
403
404void font_data_set_style(FontData* thiz, const char* style)
405{
406	return_if_fail(thiz != NULL);
407	
408	ftk_strncpy(thiz->header.style, style, sizeof(thiz->header.style));
409
410	return;
411}
412
413void font_data_destroy(FontData* thiz)
414{
415	return_if_fail(thiz != NULL);
416
417	if(thiz != NULL)
418	{
419		if(thiz->new_created)
420		{
421			FTK_FREE(thiz->glyphs);
422			FTK_FREE(thiz->data);
423			FTK_FREE(thiz->current_glyph_data);
424		}
425		else
426		{
427			if((char*)thiz->glyphs != (char*)thiz->data)
428			{
429				FTK_FREE(thiz->glyphs);
430			}
431		}
432
433		if(thiz->current_glyph_data != NULL)
434		{
435			FTK_FREE(thiz->current_glyph_data);
436		}
437
438		FTK_FREE(thiz);
439	}
440
441	return;
442}
443
444#ifdef HAS_FONT_DATA_SAVE
445#include <stdio.h>
446Ret font_data_save(FontData* thiz, const char* file_name)
447{
448	FILE* fp = fopen(file_name, "wb+");
449	{
450		fwrite(&thiz->header, 1, sizeof(FontDataHeader), fp);
451		fwrite(thiz->glyphs, 1, sizeof(FGlyph) * thiz->header.char_nr, fp);
452		fwrite(thiz->data, 1, thiz->data_size, fp);
453		fclose(fp);
454	}
455
456	return RET_OK;
457}
458#endif
459
460#ifdef FONT_DATA_TEST
461#include <sys/types.h>
462#include <sys/stat.h>
463#include <unistd.h>
464
465int main(int argc, char* argv[])
466{
467	int ch = 'a';
468	int length = 0;
469	char* buffer = NULL;
470	Glyph ret_glyph = {0};
471	FontData* data = font_data_create(36, 0);
472	Glyph* glyph = (Glyph*)FTK_ZALLOC(sizeof(Glyph));
473
474	glyph->w = 7;
475	glyph->h = 9;
476	glyph->x = 5;
477	glyph->y = 5;
478	glyph->data = (unsigned char*) FTK_ZALLOC(glyph->w * glyph->h);
479
480	for(; ch <= 'z'; ch++)
481	{
482		glyph->code = ch;
483		assert(font_data_add_glyph(data, glyph) == RET_OK);
484	}
485	
486	for(ch='0'; ch <= '9'; ch++)
487	{
488		glyph->code = ch;
489		assert(font_data_add_glyph(data, glyph) == RET_OK);
490	}
491
492	for(ch='a'; ch <= 'z'; ch++)
493	{
494		glyph->code = ch;
495		assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
496		assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
497		assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
498	}
499	
500	for(ch='0'; ch <= '9'; ch++)
501	{
502		glyph->code = ch;
503		assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
504		assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
505		assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
506	}
507
508	font_data_set_size(data, 16, 16);
509	assert(font_data_get_width(data) == 16);
510	assert(font_data_get_height(data) == 16);
511	font_data_set_author(data, "Li XianJing <xianjimli@hotmail.com>");
512	font_data_save(data, "test.fnt");
513	font_data_destroy(data);
514
515	buffer = read_file("test.fnt", &length);
516	data = font_data_load(buffer, length);
517	assert(data != NULL);
518	for(ch='a'; ch <= 'z'; ch++)
519	{
520		glyph->code = ch;
521		assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
522		assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
523		assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
524	}
525	assert(font_data_get_version(data) == FONT_VERSION);
526	assert(strcmp(font_data_get_author(data), "Li XianJing <xianjimli@hotmail.com>") == 0);
527	font_data_destroy(data);
528	FTK_FREE(glyph->data);
529	FTK_FREE(glyph);
530
531	return 0;
532}
533#endif/*FONT_DATA_TEST*/