Mercurial > hgrepos > Python2 > PyMuPDF
view mupdf-source/source/fitz/harfbuzz.c @ 29:f76e6575dca9 v1.26.4+1
+++++ v1.26.4+1
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Fri, 19 Sep 2025 19:59:23 +0200 |
| parents | b50eed0cc0ef |
| children |
line wrap: on
line source
// Copyright (C) 2004-2021 Artifex Software, Inc. // // This file is part of MuPDF. // // MuPDF is free software: you can redistribute it and/or modify it under the // terms of the GNU Affero General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> // // Alternative licensing terms are available from the licensor. // For commercial licensing, see <https://www.artifex.com/> or contact // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, // CA 94129, USA, for further information. /* * Some additional glue functions for using Harfbuzz with * custom allocators. */ #include "mupdf/fitz.h" #if FZ_ENABLE_HTML_ENGINE #include "hb.h" #include <assert.h> /* Harfbuzz has some major design flaws (for our usage * at least). * * By default it uses malloc and free as the underlying * allocators. Thus in its default form we cannot get * a record (much less control) over how much allocation * is done. * * Harfbuzz does allow build options to control where * malloc and free go - in particular we point them at * fz_hb_malloc and fz_hb_free in our implementation. * Unfortunately, this has problems too. * * Firstly, there is no mechanism for getting a context * through the call. Most other libraries allow us to * pass a "void *" value in, and have it passed through * to arrive unchanged at the allocator functions. * * Without this rudimentary functionality, we are forced * to serialise all access to Harfbuzz. * * By taking a mutex around all calls to Harfbuzz, we * can use a static of our own to get a fz_context safely * through to the allocators. This obviously costs us * performance in the multi-threaded case. * * This does not protect us against the possibility of * other people calling harfbuzz; for instance, if we * link MuPDF into an app that either calls harfbuzz * itself, or uses another library that calls harfbuzz, * there is no guarantee that that library will take * the same lock while calling harfbuzz. This leaves * us open to the possibility of crashes. The only * way around this would be to use completely separate * harfbuzz instances. * * In order to ensure that allocations throughout mupdf * are done consistently, we get harfbuzz to call our * own fz_hb_malloc/realloc/calloc/free functions that * call down to fz_malloc/realloc/calloc/free. These * require context variables, so we get our fz_hb_lock * and unlock to set these. Any attempt to call through * without setting these will be detected. * * It is therefore vital that any fz_lock/fz_unlock * handlers are shared between all the fz_contexts in * use at a time. * * Secondly, Harfbuzz allocates some 'internal' memory * on the first call, and leaves this linked from static * variables. By default, this data is never freed back. * This means it is impossible to clear the library back * to a default state. Memory debugging will always show * Harfbuzz as having leaked a set amount of memory. * * There is a mechanism in Harfbuzz for freeing these * blocks - that of building with HAVE_ATEXIT. This * causes the blocks to be freed back on exit, but a) * this doesn't reset the fz_context value, so we can't * free them correctly, and b) any fz_context value it * did keep would already have been closed down due to * the program exit. * * In addition, because of these everlasting blocks, we * cannot safely call Harfbuzz after we close down any * allocator that Harfbuzz has been using (because * Harfbuzz may still be holding pointers to data within * that allocators managed space). * * There is nothing we can do about the leaking blocks * except to add some hacks to our memory debugging * library to allow it to suppress the blocks that * harfbuzz leaks. * * Consequently, we leave them to leak, and warn Memento * about this. */ /* Potentially we can write different versions * of get_context and set_context for different * threading systems. * * This simple version relies on harfbuzz never * trying to make 2 allocations at once on * different threads. The only way that can happen * is when one of those other threads is someone * outside MuPDF calling harfbuzz while MuPDF * is running. This will cause us such huge * problems that for now, we'll just forbid it. */ static fz_context *fz_hb_secret = NULL; static void set_hb_context(fz_context *ctx) { fz_hb_secret = ctx; } static fz_context *get_hb_context(void) { return fz_hb_secret; } void fz_hb_lock(fz_context *ctx) { fz_ft_lock(ctx); set_hb_context(ctx); } void fz_hb_unlock(fz_context *ctx) { set_hb_context(NULL); fz_ft_unlock(ctx); } void *fz_hb_malloc(size_t size) { fz_context *ctx = get_hb_context(); assert(ctx != NULL); return Memento_label(fz_malloc_no_throw(ctx, size), "hb"); } void *fz_hb_calloc(size_t n, size_t size) { fz_context *ctx = get_hb_context(); assert(ctx != NULL); return Memento_label(fz_calloc_no_throw(ctx, n, size), "hb"); } void *fz_hb_realloc(void *ptr, size_t size) { fz_context *ctx = get_hb_context(); assert(ctx != NULL); return Memento_label(fz_realloc_no_throw(ctx, ptr, size), "hb"); } void fz_hb_free(void *ptr) { fz_context *ctx = get_hb_context(); assert(ctx != NULL); fz_free(ctx, ptr); } #endif
