harfbuzz.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. * Some additional glue functions for using Harfbuzz with
  24. * custom allocators.
  25. */
  26. #include "mupdf/fitz.h"
  27. #if FZ_ENABLE_HTML_ENGINE
  28. #include "hb.h"
  29. #include <assert.h>
  30. /* Harfbuzz has some major design flaws (for our usage
  31. * at least).
  32. *
  33. * By default it uses malloc and free as the underlying
  34. * allocators. Thus in its default form we cannot get
  35. * a record (much less control) over how much allocation
  36. * is done.
  37. *
  38. * Harfbuzz does allow build options to control where
  39. * malloc and free go - in particular we point them at
  40. * fz_hb_malloc and fz_hb_free in our implementation.
  41. * Unfortunately, this has problems too.
  42. *
  43. * Firstly, there is no mechanism for getting a context
  44. * through the call. Most other libraries allow us to
  45. * pass a "void *" value in, and have it passed through
  46. * to arrive unchanged at the allocator functions.
  47. *
  48. * Without this rudimentary functionality, we are forced
  49. * to serialise all access to Harfbuzz.
  50. *
  51. * By taking a mutex around all calls to Harfbuzz, we
  52. * can use a static of our own to get a fz_context safely
  53. * through to the allocators. This obviously costs us
  54. * performance in the multi-threaded case.
  55. *
  56. * This does not protect us against the possibility of
  57. * other people calling harfbuzz; for instance, if we
  58. * link MuPDF into an app that either calls harfbuzz
  59. * itself, or uses another library that calls harfbuzz,
  60. * there is no guarantee that that library will take
  61. * the same lock while calling harfbuzz. This leaves
  62. * us open to the possibility of crashes. The only
  63. * way around this would be to use completely separate
  64. * harfbuzz instances.
  65. *
  66. * In order to ensure that allocations throughout mupdf
  67. * are done consistently, we get harfbuzz to call our
  68. * own fz_hb_malloc/realloc/calloc/free functions that
  69. * call down to fz_malloc/realloc/calloc/free. These
  70. * require context variables, so we get our fz_hb_lock
  71. * and unlock to set these. Any attempt to call through
  72. * without setting these will be detected.
  73. *
  74. * It is therefore vital that any fz_lock/fz_unlock
  75. * handlers are shared between all the fz_contexts in
  76. * use at a time.
  77. *
  78. * Secondly, Harfbuzz allocates some 'internal' memory
  79. * on the first call, and leaves this linked from static
  80. * variables. By default, this data is never freed back.
  81. * This means it is impossible to clear the library back
  82. * to a default state. Memory debugging will always show
  83. * Harfbuzz as having leaked a set amount of memory.
  84. *
  85. * There is a mechanism in Harfbuzz for freeing these
  86. * blocks - that of building with HAVE_ATEXIT. This
  87. * causes the blocks to be freed back on exit, but a)
  88. * this doesn't reset the fz_context value, so we can't
  89. * free them correctly, and b) any fz_context value it
  90. * did keep would already have been closed down due to
  91. * the program exit.
  92. *
  93. * In addition, because of these everlasting blocks, we
  94. * cannot safely call Harfbuzz after we close down any
  95. * allocator that Harfbuzz has been using (because
  96. * Harfbuzz may still be holding pointers to data within
  97. * that allocators managed space).
  98. *
  99. * There is nothing we can do about the leaking blocks
  100. * except to add some hacks to our memory debugging
  101. * library to allow it to suppress the blocks that
  102. * harfbuzz leaks.
  103. *
  104. * Consequently, we leave them to leak, and warn Memento
  105. * about this.
  106. */
  107. /* Potentially we can write different versions
  108. * of get_context and set_context for different
  109. * threading systems.
  110. *
  111. * This simple version relies on harfbuzz never
  112. * trying to make 2 allocations at once on
  113. * different threads. The only way that can happen
  114. * is when one of those other threads is someone
  115. * outside MuPDF calling harfbuzz while MuPDF
  116. * is running. This will cause us such huge
  117. * problems that for now, we'll just forbid it.
  118. */
  119. static fz_context *fz_hb_secret = NULL;
  120. static void set_hb_context(fz_context *ctx)
  121. {
  122. fz_hb_secret = ctx;
  123. }
  124. static fz_context *get_hb_context(void)
  125. {
  126. return fz_hb_secret;
  127. }
  128. void fz_hb_lock(fz_context *ctx)
  129. {
  130. fz_ft_lock(ctx);
  131. set_hb_context(ctx);
  132. }
  133. void fz_hb_unlock(fz_context *ctx)
  134. {
  135. set_hb_context(NULL);
  136. fz_ft_unlock(ctx);
  137. }
  138. void *fz_hb_malloc(size_t size)
  139. {
  140. fz_context *ctx = get_hb_context();
  141. assert(ctx != NULL);
  142. return Memento_label(fz_malloc_no_throw(ctx, size), "hb");
  143. }
  144. void *fz_hb_calloc(size_t n, size_t size)
  145. {
  146. fz_context *ctx = get_hb_context();
  147. assert(ctx != NULL);
  148. return Memento_label(fz_calloc_no_throw(ctx, n, size), "hb");
  149. }
  150. void *fz_hb_realloc(void *ptr, size_t size)
  151. {
  152. fz_context *ctx = get_hb_context();
  153. assert(ctx != NULL);
  154. return Memento_label(fz_realloc_no_throw(ctx, ptr, size), "hb");
  155. }
  156. void fz_hb_free(void *ptr)
  157. {
  158. fz_context *ctx = get_hb_context();
  159. assert(ctx != NULL);
  160. fz_free(ctx, ptr);
  161. }
  162. #endif