Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/source/fitz/harfbuzz.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/source/fitz/harfbuzz.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,189 @@ +// 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
