draw-glyph.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  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. #include "mupdf/fitz.h"
  23. #include "draw-imp.h"
  24. #include "glyph-imp.h"
  25. #include "pixmap-imp.h"
  26. #include <string.h>
  27. #include <math.h>
  28. #define MAX_GLYPH_SIZE 256
  29. #define MAX_CACHE_SIZE (1024*1024)
  30. #define GLYPH_HASH_LEN 509
  31. typedef struct
  32. {
  33. fz_font *font;
  34. int a, b;
  35. int c, d;
  36. unsigned short gid;
  37. unsigned char e, f;
  38. int aa;
  39. } fz_glyph_key;
  40. typedef struct fz_glyph_cache_entry
  41. {
  42. fz_glyph_key key;
  43. unsigned hash;
  44. struct fz_glyph_cache_entry *lru_prev;
  45. struct fz_glyph_cache_entry *lru_next;
  46. struct fz_glyph_cache_entry *bucket_next;
  47. struct fz_glyph_cache_entry *bucket_prev;
  48. fz_glyph *val;
  49. } fz_glyph_cache_entry;
  50. struct fz_glyph_cache
  51. {
  52. int refs;
  53. size_t total;
  54. #ifndef NDEBUG
  55. int num_evictions;
  56. ptrdiff_t evicted;
  57. #endif
  58. fz_glyph_cache_entry *entry[GLYPH_HASH_LEN];
  59. fz_glyph_cache_entry *lru_head;
  60. fz_glyph_cache_entry *lru_tail;
  61. };
  62. static size_t
  63. fz_glyph_size(fz_context *ctx, fz_glyph *glyph)
  64. {
  65. if (glyph == NULL)
  66. return 0;
  67. return sizeof(fz_glyph) + glyph->size + fz_pixmap_size(ctx, glyph->pixmap);
  68. }
  69. void
  70. fz_new_glyph_cache_context(fz_context *ctx)
  71. {
  72. fz_glyph_cache *cache;
  73. cache = fz_malloc_struct(ctx, fz_glyph_cache);
  74. cache->total = 0;
  75. cache->refs = 1;
  76. ctx->glyph_cache = cache;
  77. }
  78. static void
  79. drop_glyph_cache_entry(fz_context *ctx, fz_glyph_cache_entry *entry)
  80. {
  81. fz_glyph_cache *cache = ctx->glyph_cache;
  82. if (entry->lru_next)
  83. entry->lru_next->lru_prev = entry->lru_prev;
  84. else
  85. cache->lru_tail = entry->lru_prev;
  86. if (entry->lru_prev)
  87. entry->lru_prev->lru_next = entry->lru_next;
  88. else
  89. cache->lru_head = entry->lru_next;
  90. cache->total -= fz_glyph_size(ctx, entry->val);
  91. if (entry->bucket_next)
  92. entry->bucket_next->bucket_prev = entry->bucket_prev;
  93. if (entry->bucket_prev)
  94. entry->bucket_prev->bucket_next = entry->bucket_next;
  95. else
  96. cache->entry[entry->hash] = entry->bucket_next;
  97. fz_drop_font(ctx, entry->key.font);
  98. fz_drop_glyph(ctx, entry->val);
  99. fz_free(ctx, entry);
  100. }
  101. /* The glyph cache lock is always held when this function is called. */
  102. static void
  103. do_purge(fz_context *ctx)
  104. {
  105. fz_glyph_cache *cache = ctx->glyph_cache;
  106. int i;
  107. for (i = 0; i < GLYPH_HASH_LEN; i++)
  108. {
  109. while (cache->entry[i])
  110. drop_glyph_cache_entry(ctx, cache->entry[i]);
  111. }
  112. cache->total = 0;
  113. }
  114. void
  115. fz_purge_glyph_cache(fz_context *ctx)
  116. {
  117. fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
  118. do_purge(ctx);
  119. fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
  120. }
  121. void
  122. fz_drop_glyph_cache_context(fz_context *ctx)
  123. {
  124. if (!ctx || !ctx->glyph_cache)
  125. return;
  126. fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
  127. ctx->glyph_cache->refs--;
  128. if (ctx->glyph_cache->refs == 0)
  129. {
  130. do_purge(ctx);
  131. fz_free(ctx, ctx->glyph_cache);
  132. ctx->glyph_cache = NULL;
  133. }
  134. fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
  135. }
  136. fz_glyph_cache *
  137. fz_keep_glyph_cache(fz_context *ctx)
  138. {
  139. fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
  140. ctx->glyph_cache->refs++;
  141. fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
  142. return ctx->glyph_cache;
  143. }
  144. float
  145. fz_subpixel_adjust(fz_context *ctx, fz_matrix *ctm, fz_matrix *subpix_ctm, unsigned char *qe, unsigned char *qf)
  146. {
  147. float size = fz_matrix_expansion(*ctm);
  148. int q, hq, vq, qmin;
  149. float pix_e, pix_f, r, hr, vr, rmin;
  150. /* Quantise the subpixel positions. First, in the direction of
  151. * movement (i.e. normally X). We never need more than 4 subpixel
  152. * positions for glyphs - arguably even that is too much.
  153. * Suppress this as we get larger, because it makes less impact. */
  154. if (size >= 48)
  155. q = 0, r = 0.5f;
  156. else if (size >= 24)
  157. q = 128, r = 0.25f;
  158. else
  159. q = 192, r = 0.125f;
  160. /* Then in the 'downward' direction (normally Y). */
  161. if (size >= 8)
  162. qmin = 0, rmin = 0.5f;
  163. else if (size >= 4)
  164. qmin = 128, rmin = 0.25f;
  165. else
  166. qmin = 192, rmin = 0.125f;
  167. /* Suppress subpixel antialiasing in y axis if we have a horizontal
  168. * matrix, and in x axis if we have a vertical matrix, unless we're
  169. * really small. */
  170. hq = vq = q;
  171. hr = vr = r;
  172. if (ctm->a == 0 && ctm->d == 0)
  173. hq = qmin, hr = rmin;
  174. if (ctm->b == 0 && ctm->c == 0)
  175. vq = qmin, vr = rmin;
  176. /* Split translation into pixel and subpixel parts */
  177. subpix_ctm->a = ctm->a;
  178. subpix_ctm->b = ctm->b;
  179. subpix_ctm->c = ctm->c;
  180. subpix_ctm->d = ctm->d;
  181. subpix_ctm->e = ctm->e + hr;
  182. pix_e = floorf(subpix_ctm->e);
  183. subpix_ctm->e -= pix_e;
  184. subpix_ctm->f = ctm->f + vr;
  185. pix_f = floorf(subpix_ctm->f);
  186. subpix_ctm->f -= pix_f;
  187. /* Quantise the subpixel part */
  188. *qe = (int)(subpix_ctm->e * 256) & hq;
  189. subpix_ctm->e = *qe / 256.0f;
  190. *qf = (int)(subpix_ctm->f * 256) & vq;
  191. subpix_ctm->f = *qf / 256.0f;
  192. /* Reassemble the complete translation */
  193. ctm->e = subpix_ctm->e + pix_e;
  194. ctm->f = subpix_ctm->f + pix_f;
  195. return size;
  196. }
  197. fz_glyph *
  198. fz_render_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm, fz_matrix ctm, fz_colorspace *model, const fz_stroke_state *stroke, const fz_irect *scissor, int aa)
  199. {
  200. if (fz_font_ft_face(ctx, font))
  201. {
  202. fz_matrix subpix_trm;
  203. unsigned char qe, qf;
  204. if (stroke->dash_len > 0)
  205. return NULL;
  206. (void)fz_subpixel_adjust(ctx, trm, &subpix_trm, &qe, &qf);
  207. return fz_render_ft_stroked_glyph(ctx, font, gid, subpix_trm, ctm, stroke, aa);
  208. }
  209. return fz_render_glyph(ctx, font, gid, trm, model, scissor, 1, aa);
  210. }
  211. static unsigned do_hash(unsigned char *s, int len)
  212. {
  213. unsigned val = 0;
  214. int i;
  215. for (i = 0; i < len; i++)
  216. {
  217. val += s[i];
  218. val += (val << 10);
  219. val ^= (val >> 6);
  220. }
  221. val += (val << 3);
  222. val ^= (val >> 11);
  223. val += (val << 15);
  224. return val;
  225. }
  226. static inline void
  227. move_to_front(fz_glyph_cache *cache, fz_glyph_cache_entry *entry)
  228. {
  229. if (entry->lru_prev == NULL)
  230. return; /* At front already */
  231. /* Unlink */
  232. entry->lru_prev->lru_next = entry->lru_next;
  233. if (entry->lru_next)
  234. entry->lru_next->lru_prev = entry->lru_prev;
  235. else
  236. cache->lru_tail = entry->lru_prev;
  237. /* Relink */
  238. entry->lru_next = cache->lru_head;
  239. if (entry->lru_next)
  240. entry->lru_next->lru_prev = entry;
  241. cache->lru_head = entry;
  242. entry->lru_prev = NULL;
  243. }
  244. fz_glyph *
  245. fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix *ctm, fz_colorspace *model, const fz_irect *scissor, int alpha, int aa)
  246. {
  247. fz_glyph_cache *cache;
  248. fz_glyph_key key;
  249. fz_matrix subpix_ctm;
  250. fz_irect subpix_scissor;
  251. float size;
  252. fz_glyph *val;
  253. int do_cache, locked, caching;
  254. fz_glyph_cache_entry *entry;
  255. unsigned hash;
  256. int is_ft_font = !!fz_font_ft_face(ctx, font);
  257. fz_var(locked);
  258. fz_var(caching);
  259. fz_var(val);
  260. memset(&key, 0, sizeof key);
  261. size = fz_subpixel_adjust(ctx, ctm, &subpix_ctm, &key.e, &key.f);
  262. if (size <= MAX_GLYPH_SIZE)
  263. {
  264. scissor = &fz_infinite_irect;
  265. do_cache = 1;
  266. }
  267. else
  268. {
  269. if (is_ft_font)
  270. return NULL;
  271. subpix_scissor.x0 = scissor->x0 - floorf(ctm->e);
  272. subpix_scissor.y0 = scissor->y0 - floorf(ctm->f);
  273. subpix_scissor.x1 = scissor->x1 - floorf(ctm->e);
  274. subpix_scissor.y1 = scissor->y1 - floorf(ctm->f);
  275. scissor = &subpix_scissor;
  276. do_cache = 0;
  277. }
  278. cache = ctx->glyph_cache;
  279. key.font = font;
  280. key.gid = gid;
  281. key.a = subpix_ctm.a * 65536;
  282. key.b = subpix_ctm.b * 65536;
  283. key.c = subpix_ctm.c * 65536;
  284. key.d = subpix_ctm.d * 65536;
  285. key.aa = aa;
  286. hash = do_hash((unsigned char *)&key, sizeof(key)) % GLYPH_HASH_LEN;
  287. fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
  288. entry = cache->entry[hash];
  289. while (entry)
  290. {
  291. if (memcmp(&entry->key, &key, sizeof(key)) == 0)
  292. {
  293. move_to_front(cache, entry);
  294. val = fz_keep_glyph(ctx, entry->val);
  295. fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
  296. return val;
  297. }
  298. entry = entry->bucket_next;
  299. }
  300. locked = 1;
  301. caching = 0;
  302. val = NULL;
  303. fz_try(ctx)
  304. {
  305. if (is_ft_font)
  306. {
  307. val = fz_render_ft_glyph(ctx, font, gid, subpix_ctm, aa);
  308. }
  309. else if (fz_font_t3_procs(ctx, font))
  310. {
  311. /* We drop the glyphcache here, and execute the t3
  312. * glyph code. The danger here is that some other
  313. * thread will come along, and want the same glyph
  314. * too. If it does, we may both end up rendering
  315. * pixmaps. We cope with this later on, by ensuring
  316. * that only one gets inserted into the cache. If
  317. * we insert ours to find one already there, we
  318. * abandon ours, and use the one there already.
  319. */
  320. fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
  321. locked = 0;
  322. val = fz_render_t3_glyph(ctx, font, gid, subpix_ctm, model, scissor, aa);
  323. fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
  324. locked = 1;
  325. }
  326. else
  327. {
  328. fz_warn(ctx, "assert: uninitialized font structure");
  329. }
  330. if (val && do_cache)
  331. {
  332. if (val->w < MAX_GLYPH_SIZE && val->h < MAX_GLYPH_SIZE)
  333. {
  334. /* If we throw an exception whilst caching,
  335. * just ignore the exception and carry on. */
  336. caching = 1;
  337. if (!is_ft_font)
  338. {
  339. /* We had to unlock. Someone else might
  340. * have rendered in the meantime */
  341. entry = cache->entry[hash];
  342. while (entry)
  343. {
  344. if (memcmp(&entry->key, &key, sizeof(key)) == 0)
  345. {
  346. fz_drop_glyph(ctx, val);
  347. move_to_front(cache, entry);
  348. val = fz_keep_glyph(ctx, entry->val);
  349. goto unlock_and_return_val;
  350. }
  351. entry = entry->bucket_next;
  352. }
  353. }
  354. entry = fz_malloc_struct(ctx, fz_glyph_cache_entry);
  355. entry->key = key;
  356. entry->hash = hash;
  357. entry->bucket_next = cache->entry[hash];
  358. if (entry->bucket_next)
  359. entry->bucket_next->bucket_prev = entry;
  360. cache->entry[hash] = entry;
  361. entry->val = fz_keep_glyph(ctx, val);
  362. fz_keep_font(ctx, key.font);
  363. entry->lru_next = cache->lru_head;
  364. if (entry->lru_next)
  365. entry->lru_next->lru_prev = entry;
  366. else
  367. cache->lru_tail = entry;
  368. cache->lru_head = entry;
  369. cache->total += fz_glyph_size(ctx, val);
  370. while (cache->total > MAX_CACHE_SIZE)
  371. {
  372. #ifndef NDEBUG
  373. cache->num_evictions++;
  374. cache->evicted += fz_glyph_size(ctx, cache->lru_tail->val);
  375. #endif
  376. drop_glyph_cache_entry(ctx, cache->lru_tail);
  377. }
  378. }
  379. }
  380. unlock_and_return_val:
  381. {
  382. }
  383. }
  384. fz_always(ctx)
  385. {
  386. if (locked)
  387. fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
  388. }
  389. fz_catch(ctx)
  390. {
  391. if (caching)
  392. fz_warn(ctx, "cannot encache glyph; continuing");
  393. else
  394. fz_rethrow(ctx);
  395. }
  396. return val;
  397. }
  398. fz_pixmap *
  399. fz_render_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, fz_matrix *ctm, const fz_irect *scissor, int aa)
  400. {
  401. fz_pixmap *val = NULL;
  402. unsigned char qe, qf;
  403. fz_matrix subpix_ctm;
  404. float size = fz_subpixel_adjust(ctx, ctm, &subpix_ctm, &qe, &qf);
  405. int is_ft_font = !!fz_font_ft_face(ctx, font);
  406. if (size <= MAX_GLYPH_SIZE)
  407. {
  408. scissor = &fz_infinite_irect;
  409. }
  410. else
  411. {
  412. if (is_ft_font)
  413. return NULL;
  414. }
  415. if (is_ft_font)
  416. {
  417. val = fz_render_ft_glyph_pixmap(ctx, font, gid, subpix_ctm, aa);
  418. }
  419. else if (fz_font_t3_procs(ctx, font))
  420. {
  421. val = fz_render_t3_glyph_pixmap(ctx, font, gid, subpix_ctm, NULL, scissor, aa);
  422. }
  423. else
  424. {
  425. fz_warn(ctx, "assert: uninitialized font structure");
  426. val = NULL;
  427. }
  428. return val;
  429. }
  430. void
  431. fz_dump_glyph_cache_stats(fz_context *ctx, fz_output *out)
  432. {
  433. fz_glyph_cache *cache = ctx->glyph_cache;
  434. fz_write_printf(ctx, out, "Glyph Cache Size: %zu\n", cache->total);
  435. #ifndef NDEBUG
  436. fz_write_printf(ctx, out, "Glyph Cache Evictions: %d (%zu bytes)\n", cache->num_evictions, cache->evicted);
  437. #endif
  438. }