/src/canvas/default/fontdata.c

http://ftk.googlecode.com/ · C · 533 lines · 419 code · 85 blank · 29 comment · 86 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. * History:
  26. * ================================================================
  27. * 2009-09-11 Li XianJing <xianjimli@hotmail.com> created
  28. *
  29. */
  30. #include "fontdata.h"
  31. #ifdef WITHOUT_FTK
  32. #define FTK_ALLOC malloc
  33. #define FTK_FREE free
  34. #define FTK_ZALLOC(s) calloc(1, s)
  35. #define FTK_REALLOC realloc
  36. #else
  37. #include "ftk_log.h"
  38. #include "ftk_allocator.h"
  39. #endif
  40. #define FONT_VERSION 0x00000101 /*1.01*/
  41. typedef struct _FontDataHeader
  42. {
  43. unsigned int version;
  44. unsigned int char_nr;
  45. unsigned char width;
  46. unsigned char height;
  47. unsigned short encoding;
  48. unsigned int unused;
  49. char author[64];
  50. char family[32];
  51. char style[32];
  52. }FontDataHeader;
  53. typedef struct _FGlyph
  54. {
  55. signed char x;
  56. signed char y;
  57. unsigned char w;
  58. unsigned char h;
  59. unsigned short code;
  60. unsigned short unused;
  61. unsigned offset;
  62. }FGlyph;
  63. struct _FontData
  64. {
  65. FontDataHeader header;
  66. FGlyph* glyphs;
  67. unsigned data_size;
  68. unsigned data_buffer_size;
  69. unsigned char* data;
  70. void* org_data;
  71. int new_created;
  72. char file_name[260];
  73. void* current_glyph_data;
  74. unsigned current_glyph_data_size;
  75. };
  76. static Ret font_data_read_glyph(FontData* thiz, unsigned offset, unsigned size, Glyph* glyph);
  77. FontData* font_data_create(int char_nr, Encoding encoding)
  78. {
  79. FontData* thiz = (FontData*)FTK_ZALLOC(sizeof(FontData));
  80. if(thiz != NULL)
  81. {
  82. thiz->header.version = FONT_VERSION;
  83. thiz->header.char_nr = char_nr;
  84. thiz->header.encoding = encoding;
  85. if(char_nr > 0)
  86. {
  87. thiz->new_created = 1;
  88. thiz->glyphs = (FGlyph*)FTK_ZALLOC(char_nr * sizeof(FGlyph));
  89. }
  90. }
  91. return thiz;
  92. }
  93. FontData* font_data_load(char* data, unsigned length)
  94. {
  95. FontData* thiz = font_data_create(0, 0);
  96. return_val_if_fail(data != NULL && length > sizeof(FontDataHeader), NULL);
  97. if(thiz != NULL)
  98. {
  99. int glyph_size = 0;
  100. thiz->header = *(FontDataHeader*)data;
  101. glyph_size = thiz->header.char_nr * sizeof(FGlyph);
  102. thiz->glyphs = (FGlyph*)(data + sizeof(FontDataHeader));
  103. thiz->data = (unsigned char*)(data + sizeof(FontDataHeader) + glyph_size);
  104. thiz->data_size = length - ((char*)thiz->data - data);
  105. thiz->data_buffer_size = thiz->data_size;
  106. thiz->new_created = 0;
  107. thiz->org_data = data;
  108. }
  109. return thiz;
  110. }
  111. #ifdef WITHOUT_FTK
  112. #include <unistd.h>
  113. #include <sys/types.h>
  114. #include <sys/stat.h>
  115. char* read_file(const char* file_name, int* length)
  116. {
  117. struct stat st = {0};
  118. if(stat(file_name, &st))
  119. {
  120. return NULL;
  121. }
  122. else
  123. {
  124. char* buffer = malloc(st.st_size + 1);
  125. FILE* fp = fopen(file_name, "rb");
  126. fread(buffer, 1, st.st_size, fp);
  127. fclose(fp);
  128. buffer[st.st_size] = '\0';
  129. *length = st.st_size;
  130. return buffer;
  131. }
  132. }
  133. FontData* font_data_load_file(const char* file_name)
  134. {
  135. int length = 0;
  136. char* buffer = read_file(file_name, &length);
  137. return font_data_load(buffer, length);
  138. }
  139. static Ret font_data_read_glyph(FontData* thiz, unsigned offset, unsigned size, Glyph* glyph)
  140. {
  141. return RET_FAIL;
  142. }
  143. #else
  144. #include "ftk_file_system.h"
  145. FontData* font_data_load_file(const char* file_name)
  146. {
  147. FontData* thiz = NULL;
  148. return_val_if_fail(file_name != NULL, NULL);
  149. if((thiz = font_data_create(0, 0)) != NULL)
  150. {
  151. FtkFsHandle fp = ftk_file_open(file_name, "rb");
  152. if(fp != NULL)
  153. {
  154. int ret = 0;
  155. unsigned glyphs_size = 0;
  156. ret = ftk_file_read(fp, &thiz->header, sizeof(thiz->header));
  157. assert(ret == sizeof(thiz->header));
  158. glyphs_size = thiz->header.char_nr * sizeof(FGlyph);
  159. thiz->glyphs = (FGlyph*)FTK_ZALLOC(glyphs_size);
  160. assert(thiz->glyphs != NULL);
  161. ftk_file_read(fp, thiz->glyphs, glyphs_size);
  162. thiz->data = NULL;
  163. thiz->data_size = 0;
  164. thiz->new_created = 0;
  165. thiz->org_data = NULL;
  166. ftk_file_close(fp);
  167. ftk_strncpy(thiz->file_name, file_name, sizeof(thiz->file_name)-1);
  168. }
  169. else
  170. {
  171. FTK_FREE(thiz);
  172. }
  173. }
  174. return thiz;
  175. }
  176. static Ret font_data_read_glyph(FontData* thiz, unsigned offset, unsigned size, Glyph* glyph)
  177. {
  178. int ret = 0;
  179. FtkFsHandle fp = ftk_file_open(thiz->file_name, "rb");
  180. unsigned skip = sizeof(thiz->header) + thiz->header.char_nr * sizeof(FGlyph) + offset;
  181. return_val_if_fail(fp != NULL && glyph != NULL, RET_FAIL);
  182. ret = ftk_file_seek(fp, skip);
  183. assert(ret == 0);
  184. if(thiz->current_glyph_data_size < size)
  185. {
  186. FTK_FREE(thiz->current_glyph_data);
  187. thiz->current_glyph_data = FTK_ALLOC(size * 2);
  188. thiz->current_glyph_data_size = size * 2;
  189. }
  190. ret = ftk_file_read(fp, thiz->current_glyph_data, size);
  191. ftk_logd("%s: offset=%d size=%d ret=%d\n", __func__, offset, size, ret);
  192. ftk_file_close(fp);
  193. assert(ret == size);
  194. glyph->data = thiz->current_glyph_data;
  195. return RET_OK;
  196. }
  197. #endif
  198. Ret font_data_add_glyph(FontData* thiz, Glyph* glyph)
  199. {
  200. unsigned i = 0;
  201. return_val_if_fail(thiz != NULL && glyph != NULL && thiz->new_created, RET_FAIL);
  202. for(i = 0; i < thiz->header.char_nr; i++)
  203. {
  204. if(thiz->glyphs[i].code == glyph->code)
  205. {
  206. return RET_FOUND;
  207. }
  208. if(thiz->glyphs[i].code > glyph->code || thiz->glyphs[i].code == 0)
  209. {
  210. unsigned size = glyph->w * glyph->h;
  211. if(thiz->glyphs[i].code > glyph->code)
  212. {
  213. unsigned k = 0;
  214. for(k = thiz->header.char_nr - 1; k > i; k--)
  215. {
  216. thiz->glyphs[k] = thiz->glyphs[k-1];
  217. }
  218. }
  219. if((thiz->data_size + size) >= thiz->data_buffer_size)
  220. {
  221. unsigned data_buffer_size = thiz->data_buffer_size + (thiz->data_buffer_size >> 1) + (size << 4);
  222. unsigned char* data = (unsigned char*)FTK_REALLOC(thiz->data, data_buffer_size);
  223. if(data != NULL)
  224. {
  225. thiz->data = data;
  226. thiz->data_buffer_size = data_buffer_size;
  227. }
  228. }
  229. if((thiz->data_size + size) < thiz->data_buffer_size)
  230. {
  231. memcpy(thiz->data + thiz->data_size, glyph->data, size);
  232. thiz->glyphs[i].offset = thiz->data_size;
  233. thiz->glyphs[i].x = glyph->x;
  234. thiz->glyphs[i].y = glyph->y;
  235. thiz->glyphs[i].w = glyph->w;
  236. thiz->glyphs[i].h = glyph->h;
  237. thiz->glyphs[i].code = glyph->code;
  238. thiz->glyphs[i].unused = glyph->unused;
  239. thiz->data_size += size;
  240. }
  241. else
  242. return RET_OUT_OF_SPACE;
  243. return RET_OK;
  244. }
  245. }
  246. return RET_FAIL;
  247. }
  248. Ret font_data_get_glyph(FontData* thiz, unsigned short code, Glyph* glyph)
  249. {
  250. int low = 0;
  251. int mid = 0;
  252. int high = 0;
  253. int result = 0;
  254. return_val_if_fail(thiz != NULL && glyph != NULL, RET_FAIL);
  255. high = thiz->header.char_nr;
  256. while(low <= high)
  257. {
  258. mid = low + ((high - low) >> 1);
  259. result = thiz->glyphs[mid].code - code;
  260. if(result == 0)
  261. {
  262. glyph->x = thiz->glyphs[mid].x;
  263. glyph->y = thiz->glyphs[mid].y;
  264. glyph->w = thiz->glyphs[mid].w;
  265. glyph->h = thiz->glyphs[mid].h;
  266. glyph->code = thiz->glyphs[mid].code;
  267. glyph->unused = thiz->glyphs[mid].unused;
  268. if(thiz->data != NULL)
  269. {
  270. glyph->data = (unsigned char*)(thiz->data + (int)(thiz->glyphs[mid].offset));
  271. }
  272. else
  273. {
  274. font_data_read_glyph(thiz, thiz->glyphs[mid].offset, glyph->w * glyph->h, glyph);
  275. }
  276. return RET_OK;
  277. }
  278. else if(result < 0)
  279. {
  280. low = mid + 1;
  281. }
  282. else
  283. {
  284. high = mid - 1;
  285. }
  286. }
  287. return RET_FAIL;
  288. }
  289. int font_data_get_version(FontData* thiz)
  290. {
  291. return_val_if_fail(thiz != NULL, 0);
  292. return thiz->header.version;
  293. }
  294. int font_data_get_width(FontData* thiz)
  295. {
  296. return_val_if_fail(thiz != NULL, 0);
  297. return thiz->header.width;
  298. }
  299. int font_data_get_height(FontData* thiz)
  300. {
  301. return_val_if_fail(thiz != NULL, 0);
  302. return thiz->header.height;
  303. }
  304. const char* font_data_get_author(FontData* thiz)
  305. {
  306. return_val_if_fail(thiz != NULL, NULL);
  307. return thiz->header.author;
  308. }
  309. const char* font_data_get_family(FontData* thiz)
  310. {
  311. return_val_if_fail(thiz != NULL, NULL);
  312. return thiz->header.family;
  313. }
  314. const char* font_data_get_style(FontData* thiz)
  315. {
  316. return_val_if_fail(thiz != NULL, NULL);
  317. return thiz->header.style;
  318. }
  319. void font_data_set_size(FontData* thiz, int width, int height)
  320. {
  321. return_if_fail(thiz != NULL);
  322. thiz->header.width = width;
  323. thiz->header.height = height;
  324. return;
  325. }
  326. void font_data_set_author(FontData* thiz, const char* author)
  327. {
  328. return_if_fail(thiz != NULL);
  329. ftk_strncpy(thiz->header.author, author, sizeof(thiz->header.author));
  330. return;
  331. }
  332. void font_data_set_family(FontData* thiz, const char* family)
  333. {
  334. return_if_fail(thiz != NULL);
  335. ftk_strncpy(thiz->header.family, family, sizeof(thiz->header.family));
  336. return;
  337. }
  338. void font_data_set_style(FontData* thiz, const char* style)
  339. {
  340. return_if_fail(thiz != NULL);
  341. ftk_strncpy(thiz->header.style, style, sizeof(thiz->header.style));
  342. return;
  343. }
  344. void font_data_destroy(FontData* thiz)
  345. {
  346. return_if_fail(thiz != NULL);
  347. if(thiz != NULL)
  348. {
  349. if(thiz->new_created)
  350. {
  351. FTK_FREE(thiz->glyphs);
  352. FTK_FREE(thiz->data);
  353. FTK_FREE(thiz->current_glyph_data);
  354. }
  355. else
  356. {
  357. if((char*)thiz->glyphs != (char*)thiz->data)
  358. {
  359. FTK_FREE(thiz->glyphs);
  360. }
  361. }
  362. if(thiz->current_glyph_data != NULL)
  363. {
  364. FTK_FREE(thiz->current_glyph_data);
  365. }
  366. FTK_FREE(thiz);
  367. }
  368. return;
  369. }
  370. #ifdef HAS_FONT_DATA_SAVE
  371. #include <stdio.h>
  372. Ret font_data_save(FontData* thiz, const char* file_name)
  373. {
  374. FILE* fp = fopen(file_name, "wb+");
  375. {
  376. fwrite(&thiz->header, 1, sizeof(FontDataHeader), fp);
  377. fwrite(thiz->glyphs, 1, sizeof(FGlyph) * thiz->header.char_nr, fp);
  378. fwrite(thiz->data, 1, thiz->data_size, fp);
  379. fclose(fp);
  380. }
  381. return RET_OK;
  382. }
  383. #endif
  384. #ifdef FONT_DATA_TEST
  385. #include <sys/types.h>
  386. #include <sys/stat.h>
  387. #include <unistd.h>
  388. int main(int argc, char* argv[])
  389. {
  390. int ch = 'a';
  391. int length = 0;
  392. char* buffer = NULL;
  393. Glyph ret_glyph = {0};
  394. FontData* data = font_data_create(36, 0);
  395. Glyph* glyph = (Glyph*)FTK_ZALLOC(sizeof(Glyph));
  396. glyph->w = 7;
  397. glyph->h = 9;
  398. glyph->x = 5;
  399. glyph->y = 5;
  400. glyph->data = (unsigned char*) FTK_ZALLOC(glyph->w * glyph->h);
  401. for(; ch <= 'z'; ch++)
  402. {
  403. glyph->code = ch;
  404. assert(font_data_add_glyph(data, glyph) == RET_OK);
  405. }
  406. for(ch='0'; ch <= '9'; ch++)
  407. {
  408. glyph->code = ch;
  409. assert(font_data_add_glyph(data, glyph) == RET_OK);
  410. }
  411. for(ch='a'; ch <= 'z'; ch++)
  412. {
  413. glyph->code = ch;
  414. assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
  415. assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
  416. assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
  417. }
  418. for(ch='0'; ch <= '9'; ch++)
  419. {
  420. glyph->code = ch;
  421. assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
  422. assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
  423. assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
  424. }
  425. font_data_set_size(data, 16, 16);
  426. assert(font_data_get_width(data) == 16);
  427. assert(font_data_get_height(data) == 16);
  428. font_data_set_author(data, "Li XianJing <xianjimli@hotmail.com>");
  429. font_data_save(data, "test.fnt");
  430. font_data_destroy(data);
  431. buffer = read_file("test.fnt", &length);
  432. data = font_data_load(buffer, length);
  433. assert(data != NULL);
  434. for(ch='a'; ch <= 'z'; ch++)
  435. {
  436. glyph->code = ch;
  437. assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
  438. assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
  439. assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
  440. }
  441. assert(font_data_get_version(data) == FONT_VERSION);
  442. assert(strcmp(font_data_get_author(data), "Li XianJing <xianjimli@hotmail.com>") == 0);
  443. font_data_destroy(data);
  444. FTK_FREE(glyph->data);
  445. FTK_FREE(glyph);
  446. return 0;
  447. }
  448. #endif/*FONT_DATA_TEST*/