font.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 4; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2009-2011, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // Copyright (c) 2011-2017, SDLPAL development team.
  5. // All rights reserved.
  6. //
  7. // This file is part of SDLPAL.
  8. //
  9. // SDLPAL is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU General Public License as published by
  11. // the Free Software Foundation, either version 3 of the License, or
  12. // (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. // GNU General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public License
  20. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. //
  22. #include "font.h"
  23. #include "util.h"
  24. #include "text.h"
  25. #define _FONT_C
  26. #include "fontglyph.h"
  27. #include "fontglyph_cn.h"
  28. #include "fontglyph_tw.h"
  29. #include "fontglyph_jp.h"
  30. #include "ascii.h"
  31. static int _font_height = 16;
  32. static uint8_t reverseBits(uint8_t x) {
  33. uint8_t y = 0;
  34. for (int i = 0 ; i < 8; i++){
  35. y <<= 1;
  36. y |= (x & 1);
  37. x >>= 1;
  38. }
  39. return y;
  40. }
  41. #ifdef DEBUG
  42. void dump_font(BYTE *buf,int rows, int cols)
  43. {
  44. for(int row=0;row<rows;row++)
  45. {
  46. for( int bit=0;bit<cols;bit++)
  47. if( buf[row] & (uint8_t)pow(2,bit) )
  48. printf("*");
  49. else
  50. printf(" ");
  51. printf("\n");
  52. }
  53. }
  54. static uint16_t reverseBits16(uint16_t x)
  55. {
  56. //specified to unifont structure; not common means
  57. uint8_t l = reverseBits(x);
  58. uint8_t h = reverseBits(x >> 8);
  59. return h << 8 | l;
  60. }
  61. void dump_font16(WORD *buf,int rows, int cols)
  62. {
  63. for(int row=0;row<rows;row++)
  64. {
  65. for( int bit=0;bit<cols;bit++)
  66. if( reverseBits16(buf[row]) & (uint16_t)pow(2,bit) )
  67. printf("*");
  68. else
  69. printf(" ");
  70. printf("\n");
  71. }
  72. }
  73. #endif
  74. static void PAL_LoadISOFont(void)
  75. {
  76. int i, j;
  77. for (i = 0; i < sizeof(iso_font) / 15; i++)
  78. {
  79. for (j = 0; j < 15; j++)
  80. {
  81. unicode_font[i][j] = reverseBits(iso_font[i * 15 + j]);
  82. }
  83. unicode_font[i][15] = 0;
  84. font_width[i] = 16;
  85. }
  86. }
  87. static void PAL_LoadCNFont(void)
  88. {
  89. int i;
  90. for (i = 0; i < sizeof(fontglyph_cn) / sizeof(fontglyph_cn[0]); i++)
  91. {
  92. wchar_t w = fontglyph_cn[i].code;
  93. w = (w >= unicode_upper_base) ? (w - unicode_upper_base + unicode_lower_top) : w;
  94. if (w < sizeof(unicode_font) / sizeof(unicode_font[0]))
  95. {
  96. memcpy(unicode_font[w], fontglyph_cn[i].data, 32);
  97. font_width[w] = 32;
  98. }
  99. }
  100. }
  101. static void PAL_LoadTWFont(void)
  102. {
  103. int i;
  104. for (i = 0; i < sizeof(fontglyph_tw) / sizeof(fontglyph_tw[0]); i++)
  105. {
  106. wchar_t w = fontglyph_tw[i].code;
  107. w = (w >= unicode_upper_base) ? (w - unicode_upper_base + unicode_lower_top) : w;
  108. if (w < sizeof(unicode_font) / sizeof(unicode_font[0]))
  109. {
  110. memcpy(unicode_font[w], fontglyph_tw[i].data, 32);
  111. font_width[w] = 32;
  112. }
  113. }
  114. _font_height = 15;
  115. }
  116. static void PAL_LoadJPFont(void)
  117. {
  118. int i;
  119. for (i = 0; i < sizeof(fontglyph_jp) / sizeof(fontglyph_jp[0]); i++)
  120. {
  121. wchar_t w = fontglyph_jp[i].code;
  122. w = (w >= unicode_upper_base) ? (w - unicode_upper_base + unicode_lower_top) : w;
  123. if (w < sizeof(unicode_font) / sizeof(unicode_font[0]))
  124. {
  125. memcpy(unicode_font[w], fontglyph_jp[i].data, 32);
  126. font_width[w] = 32;
  127. }
  128. }
  129. _font_height = 16;
  130. }
  131. static void PAL_LoadEmbeddedFont(void)
  132. {
  133. FILE *fp;
  134. char *char_buf;
  135. wchar_t *wchar_buf;
  136. size_t nBytes;
  137. int nChars, i;
  138. //
  139. // Load the wor16.asc file.
  140. //
  141. if (NULL == (fp = UTIL_OpenFile("wor16.asc")))
  142. {
  143. return;
  144. }
  145. //
  146. // Get the size of wor16.asc file.
  147. //
  148. fseek(fp, 0, SEEK_END);
  149. nBytes = ftell(fp);
  150. //
  151. // Allocate buffer & read all the character codes.
  152. //
  153. if (NULL == (char_buf = (char *)malloc(nBytes)))
  154. {
  155. fclose(fp);
  156. return;
  157. }
  158. fseek(fp, 0, SEEK_SET);
  159. if (fread(char_buf, 1, nBytes, fp) < nBytes)
  160. {
  161. fclose(fp);
  162. return;
  163. }
  164. //
  165. // Close wor16.asc file.
  166. //
  167. fclose(fp);
  168. //
  169. // Detect the codepage of 'wor16.asc' and exit if not BIG5 or probability < 99
  170. // Note: 100% probability is impossible as the function does not recognize some special
  171. // characters such as bopomofo that may be used by 'wor16.asc'.
  172. //
  173. if (PAL_DetectCodePageForString(char_buf, nBytes, CP_BIG5, &i) != CP_BIG5 || i < 99)
  174. {
  175. free(char_buf);
  176. return;
  177. }
  178. //
  179. // Convert characters into unicode
  180. // Explictly specify BIG5 here for compatibility with codepage auto-detection
  181. //
  182. nChars = PAL_MultiByteToWideCharCP(CP_BIG5, char_buf, nBytes, NULL, 0);
  183. if (NULL == (wchar_buf = (wchar_t *)malloc(nChars * sizeof(wchar_t))))
  184. {
  185. free(char_buf);
  186. return;
  187. }
  188. PAL_MultiByteToWideCharCP(CP_BIG5, char_buf, nBytes, wchar_buf, nChars);
  189. free(char_buf);
  190. //
  191. // Read bitmaps from wor16.fon file.
  192. //
  193. fp = UTIL_OpenFile("wor16.fon");
  194. //
  195. // The font glyph data begins at offset 0x682 in wor16.fon.
  196. //
  197. fseek(fp, 0x682, SEEK_SET);
  198. //
  199. // Replace the original fonts
  200. //
  201. for (i = 0; i < nChars; i++)
  202. {
  203. wchar_t w = (wchar_buf[i] >= unicode_upper_base) ? (wchar_buf[i] - unicode_upper_base + unicode_lower_top) : wchar_buf[i];
  204. if (fread(unicode_font[w], 30, 1, fp) == 1)
  205. {
  206. unicode_font[w][30] = 0;
  207. unicode_font[w][31] = 0;
  208. }
  209. font_width[w] = 32;
  210. }
  211. free(wchar_buf);
  212. fclose(fp);
  213. _font_height = 15;
  214. }
  215. INT
  216. PAL_LoadUserFont(
  217. LPCSTR pszBdfFileName
  218. )
  219. /*++
  220. Purpose:
  221. Loads a BDF bitmap font file.
  222. Parameters:
  223. [IN] pszBdfFileName - Name of BDF bitmap font file..
  224. Return value:
  225. 0 = success, -1 = failure.
  226. --*/
  227. {
  228. char buf[4096];
  229. int state = 0, fstate = 0;
  230. int codepage = -1;
  231. DWORD dwEncoding = 0;
  232. BYTE bFontGlyph[32] = {0};
  233. int iCurHeight = 0;
  234. int bbw = 0, bbh = 0, bbox, bboy;
  235. FILE *fp = UTIL_OpenFileForMode(pszBdfFileName, "r");
  236. if (fp == NULL)
  237. {
  238. return -1;
  239. }
  240. _font_height = 16;
  241. while (fgets(buf, 4096, fp) != NULL)
  242. {
  243. if (state == 0)
  244. {
  245. if (strncmp(buf, "CHARSET_REGISTRY", 16) == 0)
  246. {
  247. if (strcasestr(buf, "Big5") != NULL)
  248. {
  249. codepage = CP_BIG5;
  250. }
  251. else if (strcasestr(buf, "GBK") != NULL || strcasestr(buf, "GB2312") != NULL)
  252. {
  253. codepage = CP_GBK;
  254. }
  255. else if (strcasestr(buf, "ISO10646") != NULL)
  256. {
  257. codepage = CP_UCS;
  258. }
  259. //else if (strstr(buf, "JISX0208") != NULL)
  260. //
  261. // codepage = CP_JISX0208;
  262. //}
  263. else
  264. {
  265. TerminateOnError("Charset of %s is %s, which is not a supported yet.",pszBdfFileName,buf);
  266. }
  267. }
  268. else if (strncmp(buf, "ENCODING", 8) == 0)
  269. {
  270. dwEncoding = atoi(buf + 8);
  271. }
  272. else if (strncmp(buf, "SIZE", 3) == 0)
  273. {
  274. int bytes_consumed = 0, bytes_now;
  275. int got_size;
  276. BOOL got_expected = FALSE;
  277. char size[10];
  278. sscanf(buf + bytes_consumed, "%s%n", size, &bytes_now);
  279. bytes_consumed += bytes_now;
  280. while (sscanf(buf + bytes_consumed, "%d%n", &got_size, &bytes_now))
  281. {
  282. bytes_consumed += bytes_now;
  283. if (got_size == 16 || got_size == 15)
  284. {
  285. _font_height = got_size;
  286. got_expected = TRUE;
  287. }
  288. }
  289. if (!got_expected)
  290. TerminateOnError("%s not contains expected font size 15/16!", pszBdfFileName);
  291. }
  292. else if (strncmp(buf, "BBX", 3) == 0)
  293. {
  294. int bytes_consumed = 0, bytes_now;
  295. char bbx[10];
  296. sscanf(buf+bytes_consumed,"%s%n",bbx,&bytes_now);bytes_consumed += bytes_now;
  297. sscanf(buf+bytes_consumed,"%d%n",&bbw,&bytes_now);bytes_consumed += bytes_now;
  298. sscanf(buf+bytes_consumed,"%d%n",&bbh,&bytes_now);bytes_consumed += bytes_now;
  299. sscanf(buf+bytes_consumed,"%d%n",&bbox,&bytes_now);bytes_consumed += bytes_now;
  300. sscanf(buf+bytes_consumed,"%d%n",&bboy,&bytes_now);bytes_consumed += bytes_now;
  301. }
  302. else if (strncmp(buf, "BITMAP", 6) == 0)
  303. {
  304. state = 1;
  305. iCurHeight = 0;
  306. for(iCurHeight=0;iCurHeight<bboy;iCurHeight++){
  307. bFontGlyph[iCurHeight * 2] = 0;
  308. bFontGlyph[iCurHeight * 2 + 1] = 0;
  309. }
  310. memset(bFontGlyph, 0, sizeof(bFontGlyph));
  311. }
  312. }
  313. else if (state == 1)
  314. {
  315. if (strncmp(buf, "ENDCHAR", 7) == 0)
  316. {
  317. //
  318. // Replace the original fonts
  319. //
  320. BYTE szCp[3];
  321. szCp[0] = (dwEncoding >> 8) & 0xFF;
  322. szCp[1] = dwEncoding & 0xFF;
  323. szCp[2] = 0;
  324. if (codepage == CP_GBK && dwEncoding > 0xFF)
  325. {
  326. szCp[0] |= 0x80;
  327. szCp[1] |= 0x80;
  328. }
  329. wchar_t wc[2] = { 0 };
  330. PAL_MultiByteToWideCharCP(codepage, (LPCSTR)szCp, 2, wc, 1);
  331. if (wc[0] != 0)
  332. {
  333. wchar_t w = (wc[0] >= unicode_upper_base) ? (wc[0] - unicode_upper_base + unicode_lower_top) : wc[0];
  334. if (w < sizeof(unicode_font) / sizeof(unicode_font[0]))
  335. {
  336. memcpy(unicode_font[w], bFontGlyph, sizeof(bFontGlyph));
  337. }
  338. }
  339. state = 0;
  340. }
  341. else
  342. {
  343. if (iCurHeight < bbh )
  344. {
  345. WORD wCode = strtoul(buf, NULL, 16);
  346. if(bbw <= 8)
  347. {
  348. switch(fstate)
  349. {
  350. case 0:
  351. bFontGlyph[iCurHeight * 2] = wCode;
  352. fstate = 1;
  353. break;
  354. case 1:
  355. bFontGlyph[iCurHeight * 2+1] = wCode;
  356. fstate = 0;
  357. iCurHeight++;
  358. break;
  359. }
  360. }else{
  361. bFontGlyph[iCurHeight * 2] = (wCode >> 8);
  362. bFontGlyph[iCurHeight * 2 + 1] = (wCode & 0xFF);
  363. iCurHeight++;
  364. }
  365. }
  366. }
  367. }
  368. }
  369. fclose(fp);
  370. return 0;
  371. }
  372. int
  373. PAL_InitFont(
  374. const CONFIGURATION* cfg
  375. )
  376. {
  377. if (!cfg->pszMsgFile)
  378. {
  379. PAL_LoadEmbeddedFont();
  380. }
  381. if (g_TextLib.fUseISOFont)
  382. {
  383. PAL_LoadISOFont();
  384. }
  385. if (cfg->pszFontFile)
  386. {
  387. PAL_LoadUserFont(cfg->pszFontFile);
  388. }
  389. else if (_font_height != 15)
  390. {
  391. switch (g_TextLib.iFontFlavor)
  392. {
  393. case kFontFlavorAuto:
  394. switch (PAL_GetCodePage())
  395. {
  396. case CP_GBK:
  397. PAL_LoadCNFont();
  398. break;
  399. case CP_BIG5:
  400. PAL_LoadTWFont();
  401. break;
  402. default:
  403. break;
  404. }
  405. break;
  406. case kFontFlavorSimpChin:
  407. PAL_LoadCNFont();
  408. break;
  409. case kFontFlavorTradChin:
  410. PAL_LoadTWFont();
  411. break;
  412. case kFontFlavorJapanese:
  413. PAL_LoadJPFont();
  414. break;
  415. case kFontFlavorUnifont:
  416. default:
  417. break;
  418. }
  419. }
  420. return 0;
  421. }
  422. void
  423. PAL_FreeFont(
  424. void
  425. )
  426. {
  427. }
  428. void
  429. PAL_DrawCharOnSurface(
  430. uint16_t wChar,
  431. SDL_Surface *lpSurface,
  432. PAL_POS pos,
  433. uint8_t bColor,
  434. BOOL fUse8x8Font
  435. )
  436. {
  437. int i, j;
  438. int x = PAL_X(pos), y = PAL_Y(pos);
  439. //
  440. // Check for NULL pointer & invalid char code.
  441. //
  442. if (lpSurface == NULL || (wChar >= unicode_lower_top && wChar < unicode_upper_base) ||
  443. wChar >= unicode_upper_top || (_font_height == 8 && wChar >= 0x100))
  444. {
  445. return;
  446. }
  447. //
  448. // Locate for this character in the font lib.
  449. //
  450. if (wChar >= unicode_upper_base)
  451. {
  452. wChar -= (unicode_upper_base - unicode_lower_top);
  453. }
  454. //
  455. // Draw the character to the surface.
  456. //
  457. LPBYTE dest = (LPBYTE)lpSurface->pixels + y * lpSurface->pitch + x;
  458. LPBYTE top = (LPBYTE)lpSurface->pixels + lpSurface->h * lpSurface->pitch;
  459. if (fUse8x8Font)
  460. {
  461. for (i = 0; i < 8 && dest < top; i++, dest += lpSurface->pitch)
  462. {
  463. for (j = 0; j < 8 && x + j < lpSurface->w; j++)
  464. {
  465. if (iso_font_8x8[wChar][i] & (1 << j))
  466. {
  467. dest[j] = bColor;
  468. }
  469. }
  470. }
  471. }
  472. else
  473. {
  474. if (font_width[wChar] == 32)
  475. {
  476. for (i = 0; i < _font_height * 2 && dest < top; i += 2, dest += lpSurface->pitch)
  477. {
  478. for (j = 0; j < 8 && x + j < lpSurface->w; j++)
  479. {
  480. if (unicode_font[wChar][i] & (1 << (7 - j)))
  481. {
  482. dest[j] = bColor;
  483. }
  484. }
  485. for (j = 0; j < 8 && x + j + 8 < lpSurface->w; j++)
  486. {
  487. if (unicode_font[wChar][i + 1] & (1 << (7 - j)))
  488. {
  489. dest[j + 8] = bColor;
  490. }
  491. }
  492. }
  493. }
  494. else
  495. {
  496. for (i = 0; i < _font_height && dest < top; i++, dest += lpSurface->pitch)
  497. {
  498. for (j = 0; j < 8 && x + j < lpSurface->w; j++)
  499. {
  500. if (unicode_font[wChar][i] & (1 << (7 - j)))
  501. {
  502. dest[j] = bColor;
  503. }
  504. }
  505. }
  506. }
  507. }
  508. }
  509. int
  510. PAL_CharWidth(
  511. uint16_t wChar
  512. )
  513. {
  514. if ((wChar >= unicode_lower_top && wChar < unicode_upper_base) || wChar >= unicode_upper_top)
  515. {
  516. return 0;
  517. }
  518. //
  519. // Locate for this character in the font lib.
  520. //
  521. if (wChar >= unicode_upper_base)
  522. {
  523. wChar -= (unicode_upper_base - unicode_lower_top);
  524. }
  525. return font_width[wChar] >> 1;
  526. }
  527. int
  528. PAL_FontHeight(
  529. void
  530. )
  531. {
  532. return _font_height;
  533. }