gl-font.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. // Copyright (C) 2004-2021 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. /*
  23. * A very simple font cache and rasterizer that uses FreeType
  24. * to draw fonts from a single OpenGL texture. The code uses
  25. * a linear-probe hashtable, and writes new glyphs into
  26. * the texture using glTexSubImage2D. When the texture fills
  27. * up, or the hash table gets too crowded, the cache is emptied.
  28. *
  29. * This is designed to be used for horizontal text only,
  30. * and draws unhinted text with subpixel accurate metrics
  31. * and kerning. As such, you should always call the drawing
  32. * function with an orthogonal transform that maps units
  33. * to pixels accurately.
  34. */
  35. #include "gl-app.h"
  36. #include <string.h>
  37. #include <math.h>
  38. #include <stdlib.h>
  39. #include <stdio.h>
  40. #define PADDING 1 /* set to 0 to save some space but disallow arbitrary transforms */
  41. #define MAXGLYPHS 4093 /* prime number for hash table goodness */
  42. #define CACHESIZE 1024
  43. #define XPRECISION 4
  44. #define YPRECISION 1
  45. struct key
  46. {
  47. fz_font *font;
  48. float size;
  49. short gid;
  50. unsigned char subx;
  51. unsigned char suby;
  52. };
  53. struct glyph
  54. {
  55. char lsb, top, w, h;
  56. short s, t;
  57. };
  58. struct table
  59. {
  60. struct key key;
  61. struct glyph glyph;
  62. };
  63. static struct table g_table[MAXGLYPHS];
  64. static int g_table_load = 0;
  65. static unsigned int g_cache_tex = 0;
  66. static int g_cache_w = CACHESIZE;
  67. static int g_cache_h = CACHESIZE;
  68. static int g_cache_row_y = 0;
  69. static int g_cache_row_x = 0;
  70. static int g_cache_row_h = 0;
  71. static fz_font *g_font = NULL;
  72. static void clear_font_cache(void)
  73. {
  74. #if PADDING > 0
  75. unsigned char *zero = malloc((size_t)g_cache_w * g_cache_h);
  76. memset(zero, 0, (size_t)g_cache_w * g_cache_h);
  77. glBindTexture(GL_TEXTURE_2D, g_cache_tex);
  78. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_cache_w, g_cache_h, GL_ALPHA, GL_UNSIGNED_BYTE, zero);
  79. free(zero);
  80. #endif
  81. memset(g_table, 0, sizeof(g_table));
  82. g_table_load = 0;
  83. g_cache_row_y = PADDING;
  84. g_cache_row_x = PADDING;
  85. g_cache_row_h = 0;
  86. }
  87. void ui_init_fonts(void)
  88. {
  89. const unsigned char *data;
  90. int size;
  91. glGenTextures(1, &g_cache_tex);
  92. glBindTexture(GL_TEXTURE_2D, g_cache_tex);
  93. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  94. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  95. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  96. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  97. glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g_cache_w, g_cache_h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
  98. clear_font_cache();
  99. data = fz_lookup_builtin_font(ctx, "Charis SIL", 0, 0, &size);
  100. if (!data)
  101. data = fz_lookup_builtin_font(ctx, "Times", 0, 0, &size);
  102. g_font = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0);
  103. }
  104. void ui_finish_fonts(void)
  105. {
  106. clear_font_cache();
  107. fz_drop_font(ctx, g_font);
  108. }
  109. static unsigned int hashfunc(struct key *key)
  110. {
  111. unsigned char *buf = (unsigned char *)key;
  112. unsigned int len = sizeof(struct key);
  113. unsigned int h = 0;
  114. while (len--)
  115. h = *buf++ + (h << 6) + (h << 16) - h;
  116. return h;
  117. }
  118. static unsigned int lookup_table(struct key *key)
  119. {
  120. unsigned int pos = hashfunc(key) % MAXGLYPHS;
  121. while (1)
  122. {
  123. if (!g_table[pos].key.font) /* empty slot */
  124. return pos;
  125. if (!memcmp(key, &g_table[pos].key, sizeof(struct key))) /* matching slot */
  126. return pos;
  127. pos = (pos + 1) % MAXGLYPHS;
  128. }
  129. }
  130. static struct glyph *lookup_glyph(fz_font *font, float size, int gid, float *xp, float *yp)
  131. {
  132. fz_matrix trm, subpix_trm;
  133. unsigned char subx, suby;
  134. fz_pixmap *pixmap;
  135. struct key key;
  136. unsigned int pos;
  137. int w, h;
  138. /* match fitz's glyph cache quantization */
  139. trm = fz_scale(size, -size);
  140. trm.e = *xp;
  141. trm.f = *yp;
  142. fz_subpixel_adjust(ctx, &trm, &subpix_trm, &subx, &suby);
  143. *xp = trm.e;
  144. *yp = trm.f;
  145. /*
  146. * Look it up in the table
  147. */
  148. memset(&key, 0, sizeof key);
  149. key.font = font;
  150. key.size = size;
  151. key.gid = gid;
  152. key.subx = subx;
  153. key.suby = suby;
  154. pos = lookup_table(&key);
  155. if (g_table[pos].key.font)
  156. return &g_table[pos].glyph;
  157. /*
  158. * Render the bitmap
  159. */
  160. glEnd();
  161. pixmap = fz_render_glyph_pixmap(ctx, font, gid, &subpix_trm, NULL, 8);
  162. w = pixmap->w;
  163. h = pixmap->h;
  164. /*
  165. * Find an empty slot in the texture
  166. */
  167. if (g_table_load == (MAXGLYPHS * 3) / 4)
  168. {
  169. puts("font cache table full, clearing cache");
  170. clear_font_cache();
  171. pos = lookup_table(&key);
  172. }
  173. if (h + PADDING > g_cache_h || w + PADDING > g_cache_w)
  174. return NULL;
  175. if (g_cache_row_x + w + PADDING > g_cache_w)
  176. {
  177. g_cache_row_y += g_cache_row_h + PADDING;
  178. g_cache_row_x = PADDING;
  179. g_cache_row_h = 0;
  180. }
  181. if (g_cache_row_y + h + PADDING > g_cache_h)
  182. {
  183. puts("font cache texture full, clearing cache");
  184. clear_font_cache();
  185. pos = lookup_table(&key);
  186. }
  187. /*
  188. * Copy bitmap into texture
  189. */
  190. memcpy(&g_table[pos].key, &key, sizeof(struct key));
  191. g_table[pos].glyph.w = pixmap->w;
  192. g_table[pos].glyph.h = pixmap->h;
  193. g_table[pos].glyph.lsb = pixmap->x;
  194. g_table[pos].glyph.top = -pixmap->y;
  195. g_table[pos].glyph.s = g_cache_row_x;
  196. g_table[pos].glyph.t = g_cache_row_y;
  197. g_table_load ++;
  198. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  199. glPixelStorei(GL_UNPACK_ROW_LENGTH, pixmap->w);
  200. glTexSubImage2D(GL_TEXTURE_2D, 0, g_cache_row_x, g_cache_row_y, w, h,
  201. GL_ALPHA, GL_UNSIGNED_BYTE, pixmap->samples);
  202. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  203. fz_drop_pixmap(ctx, pixmap);
  204. glBegin(GL_QUADS);
  205. g_cache_row_x += w + PADDING;
  206. if (g_cache_row_h < h + PADDING)
  207. g_cache_row_h = h + PADDING;
  208. return &g_table[pos].glyph;
  209. }
  210. static float ui_draw_glyph(fz_font *font, float size, int gid, float x, float y)
  211. {
  212. struct glyph *glyph;
  213. float s0, t0, s1, t1, xc, yc;
  214. glyph = lookup_glyph(font, size, gid, &x, &y);
  215. if (!glyph)
  216. return 0;
  217. s0 = (float) glyph->s / g_cache_w;
  218. t0 = (float) glyph->t / g_cache_h;
  219. s1 = (float) (glyph->s + glyph->w) / g_cache_w;
  220. t1 = (float) (glyph->t + glyph->h) / g_cache_h;
  221. xc = floorf(x) + glyph->lsb;
  222. yc = floorf(y) - glyph->top + glyph->h;
  223. glTexCoord2f(s0, t0); glVertex2f(xc, yc - glyph->h);
  224. glTexCoord2f(s1, t0); glVertex2f(xc + glyph->w, yc - glyph->h);
  225. glTexCoord2f(s1, t1); glVertex2f(xc + glyph->w, yc);
  226. glTexCoord2f(s0, t1); glVertex2f(xc, yc);
  227. return fz_advance_glyph(ctx, font, gid, 0) * size;
  228. }
  229. float ui_measure_character(int c)
  230. {
  231. fz_font *font;
  232. int gid = fz_encode_character_with_fallback(ctx, g_font, c, 0, 0, &font);
  233. return fz_advance_glyph(ctx, font, gid, 0) * ui.fontsize;
  234. }
  235. static float ui_draw_character_imp(float x, float y, int c)
  236. {
  237. fz_font *font;
  238. int gid = fz_encode_character_with_fallback(ctx, g_font, c, 0, 0, &font);
  239. return ui_draw_glyph(font, ui.fontsize, gid, x, y);
  240. }
  241. static void ui_begin_text(void)
  242. {
  243. glBindTexture(GL_TEXTURE_2D, g_cache_tex);
  244. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  245. glEnable(GL_BLEND);
  246. glEnable(GL_TEXTURE_2D);
  247. glBegin(GL_QUADS);
  248. }
  249. static void ui_end_text(void)
  250. {
  251. glEnd();
  252. glDisable(GL_TEXTURE_2D);
  253. glDisable(GL_BLEND);
  254. }
  255. void ui_draw_string(float x, float y, const char *str)
  256. {
  257. int c;
  258. ui_begin_text();
  259. while (*str)
  260. {
  261. str += fz_chartorune(&c, str);
  262. x += ui_draw_character_imp(x, y + ui.baseline, c);
  263. }
  264. ui_end_text();
  265. }
  266. void ui_draw_string_part(float x, float y, const char *s, const char *e)
  267. {
  268. int c;
  269. ui_begin_text();
  270. while (s < e)
  271. {
  272. s += fz_chartorune(&c, s);
  273. x += ui_draw_character_imp(x, y + ui.baseline, c);
  274. }
  275. ui_end_text();
  276. }
  277. void ui_draw_character(float x, float y, int c)
  278. {
  279. ui_begin_text();
  280. ui_draw_character_imp(x, y + ui.baseline, c);
  281. ui_end_text();
  282. }
  283. float ui_measure_string(const char *str)
  284. {
  285. int c;
  286. float x = 0;
  287. while (*str)
  288. {
  289. str += fz_chartorune(&c, str);
  290. x += ui_measure_character(c);
  291. }
  292. return x;
  293. }
  294. float ui_measure_string_part(const char *s, const char *e)
  295. {
  296. int c;
  297. float w = 0;
  298. while (s < e)
  299. {
  300. s += fz_chartorune(&c, s);
  301. w += ui_measure_character(c);
  302. }
  303. return w;
  304. }
  305. int ui_break_lines(char *a, struct line *lines, int maxlines, int width, int *maxwidth)
  306. {
  307. char *next, *space = NULL, *b = a;
  308. int c, n = 0;
  309. float space_x, x = 0, w = 0;
  310. if (maxwidth)
  311. *maxwidth = 0;
  312. while (*b)
  313. {
  314. next = b + fz_chartorune(&c, b);
  315. if (c == '\r' || c == '\n')
  316. {
  317. if (lines && n < maxlines)
  318. {
  319. lines[n].a = a;
  320. lines[n].b = b;
  321. }
  322. ++n;
  323. if (maxwidth && *maxwidth < x)
  324. *maxwidth = x;
  325. a = next;
  326. x = 0;
  327. space = NULL;
  328. }
  329. else
  330. {
  331. if (c == ' ' && maxlines > 1)
  332. {
  333. space = b;
  334. space_x = x;
  335. }
  336. w = ui_measure_character(c);
  337. if (x + w > width)
  338. {
  339. if (space)
  340. {
  341. if (lines && n < maxlines)
  342. {
  343. lines[n].a = a;
  344. lines[n].b = space;
  345. }
  346. ++n;
  347. if (maxwidth && *maxwidth < space_x)
  348. *maxwidth = space_x;
  349. a = next = space + 1;
  350. x = 0;
  351. space = NULL;
  352. }
  353. else
  354. {
  355. if (lines && n < maxlines)
  356. {
  357. lines[n].a = a;
  358. lines[n].b = b;
  359. }
  360. ++n;
  361. if (maxwidth && *maxwidth < x)
  362. *maxwidth = x;
  363. a = b;
  364. x = w;
  365. space = NULL;
  366. }
  367. }
  368. else
  369. {
  370. x += w;
  371. }
  372. }
  373. b = next;
  374. }
  375. if (lines && n < maxlines)
  376. {
  377. lines[n].a = a;
  378. lines[n].b = b;
  379. }
  380. ++n;
  381. if (maxwidth && *maxwidth < x)
  382. *maxwidth = x;
  383. return n < maxlines ? n : maxlines;
  384. }
  385. void ui_draw_lines(float x, float y, struct line *lines, int n)
  386. {
  387. int i;
  388. for (i = 0; i < n; ++i)
  389. {
  390. ui_draw_string_part(x, y, lines[i].a, lines[i].b);
  391. y += ui.lineheight;
  392. }
  393. }