Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/include/mupdf/fitz/store.h @ 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/include/mupdf/fitz/store.h Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,465 @@ +// 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. + +#ifndef MUPDF_FITZ_STORE_H +#define MUPDF_FITZ_STORE_H + +#include "mupdf/fitz/system.h" +#include "mupdf/fitz/context.h" +#include "mupdf/fitz/output.h" +#include "mupdf/fitz/log.h" +#include "mupdf/fitz/types.h" + +/** + Resource store + + MuPDF stores decoded "objects" into a store for potential reuse. + If the size of the store gets too big, objects stored within it + can be evicted and freed to recover space. When MuPDF comes to + decode such an object, it will check to see if a version of this + object is already in the store - if it is, it will simply reuse + it. If not, it will decode it and place it into the store. + + All objects that can be placed into the store are derived from + the fz_storable type (i.e. this should be the first component of + the objects structure). This allows for consistent (thread safe) + reference counting, and includes a function that will be called + to free the object as soon as the reference count reaches zero. + + Most objects offer fz_keep_XXXX/fz_drop_XXXX functions derived + from fz_keep_storable/fz_drop_storable. Creation of such objects + includes a call to FZ_INIT_STORABLE to set up the fz_storable + header. + */ +typedef struct fz_storable fz_storable; + +/** + Function type for a function to drop a storable object. + + Objects within the store are identified by type by comparing + their drop_fn pointers. +*/ +typedef void (fz_store_drop_fn)(fz_context *, fz_storable *); + +/** + Function type for a function to check whether a storable + object can be dropped at the moment. + + Return 0 for 'cannot be dropped', 1 otherwise. +*/ +typedef int (fz_store_droppable_fn)(fz_context *, fz_storable *); + +/** + Any storable object should include an fz_storable structure + at the start (by convention at least) of their structure. + (Unless it starts with an fz_key_storable, see below). +*/ +struct fz_storable { + int refs; + fz_store_drop_fn *drop; + fz_store_droppable_fn *droppable; +}; + +/** + Any storable object that can appear in the key of another + storable object should include an fz_key_storable structure + at the start (by convention at least) of their structure. +*/ +typedef struct +{ + fz_storable storable; + short store_key_refs; +} fz_key_storable; + +/** + Macros to initialise a storable object. +*/ +#define FZ_INIT_STORABLE(S_,RC,DROP) \ + do { fz_storable *S = &(S_)->storable; S->refs = (RC); \ + S->drop = (DROP); S->droppable = NULL; \ + } while (0) + +#define FZ_INIT_AWKWARD_STORABLE(S_,RC,DROP,DROPPABLE) \ + do { fz_storable *S = &(S_)->storable; S->refs = (RC); \ + S->drop = (DROP); S->droppable = (DROPPABLE); \ + } while (0) + +/** + Macro to initialise a key storable object. +*/ +#define FZ_INIT_KEY_STORABLE(KS_,RC,DROP) \ + do { fz_key_storable *KS = &(KS_)->key_storable; KS->store_key_refs = 0;\ + FZ_INIT_STORABLE(KS,RC,DROP); \ + } while (0) + +/** + Increment the reference count for a storable object. + Returns the same pointer. + + Never throws exceptions. +*/ +void *fz_keep_storable(fz_context *, const fz_storable *); + +/** + Decrement the reference count for a storable object. When the + reference count hits zero, the drop function for that object + is called to free the object. + + Never throws exceptions. +*/ +void fz_drop_storable(fz_context *, const fz_storable *); + +/** + Increment the (normal) reference count for a key storable + object. Returns the same pointer. + + Never throws exceptions. +*/ +void *fz_keep_key_storable(fz_context *, const fz_key_storable *); + +/** + Decrement the (normal) reference count for a storable object. + When the total reference count hits zero, the drop function for + that object is called to free the object. + + Never throws exceptions. +*/ +void fz_drop_key_storable(fz_context *, const fz_key_storable *); + +/** + Increment the (key) reference count for a key storable + object. Returns the same pointer. + + Never throws exceptions. +*/ +void *fz_keep_key_storable_key(fz_context *, const fz_key_storable *); + +/** + Decrement the (key) reference count for a storable object. + When the total reference count hits zero, the drop function for + that object is called to free the object. + + Never throws exceptions. +*/ +void fz_drop_key_storable_key(fz_context *, const fz_key_storable *); + +/** + The store can be seen as a dictionary that maps keys to + fz_storable values. In order to allow keys of different types to + be stored, we have a structure full of functions for each key + 'type'; this fz_store_type pointer is stored with each key, and + tells the store how to perform certain operations (like taking/ + dropping a reference, comparing two keys, outputting details for + debugging etc). + + The store uses a hash table internally for speed where possible. + In order for this to work, we need a mechanism for turning a + generic 'key' into 'a hashable string'. For this purpose the + type structure contains a make_hash_key function pointer that + maps from a void * to a fz_store_hash structure. If + make_hash_key function returns 0, then the key is determined not + to be hashable, and the value is not stored in the hash table. + + Some objects can be used both as values within the store, and as + a component of keys within the store. We refer to these objects + as "key storable" objects. In this case, we need to take + additional care to ensure that we do not end up keeping an item + within the store, purely because its value is referred to by + another key in the store. + + An example of this are fz_images in PDF files. Each fz_image is + placed into the store to enable it to be easily reused. When the + image is rendered, a pixmap is generated from the image, and the + pixmap is placed into the store so it can be reused on + subsequent renders. The image forms part of the key for the + pixmap. + + When we close the pdf document (and any associated pages/display + lists etc), we drop the images from the store. This may leave us + in the position of the images having non-zero reference counts + purely because they are used as part of the keys for the + pixmaps. + + We therefore use special reference counting functions to keep + track of these "key storable" items, and hence store the number + of references to these items that are used in keys. + + When the number of references to an object == the number of + references to an object from keys in the store, we know that we + can remove all the items which have that object as part of the + key. This is done by running a pass over the store, 'reaping' + those items. + + Reap passes are slower than we would like as they touch every + item in the store. We therefore provide a way to 'batch' such + reap passes together, using fz_defer_reap_start/ + fz_defer_reap_end to bracket a region in which many may be + triggered. +*/ +typedef struct +{ + fz_store_drop_fn *drop; + union + { + struct + { + const void *ptr; + int i; + } pi; /* 8 or 12 bytes */ + struct + { + const void *ptr; + int i; + fz_irect r; + } pir; /* 24 or 28 bytes */ + struct + { + int id; + char has_shape; + char has_group_alpha; + float m[4]; + void *ptr; + int doc_id; + } im; /* 32 or 36 bytes */ + struct + { + unsigned char src_md5[16]; + unsigned char dst_md5[16]; + unsigned int ri:2; + unsigned int bp:1; + unsigned int format:1; + unsigned int proof:1; + unsigned int src_extras:5; + unsigned int dst_extras:5; + unsigned int copy_spots:1; + unsigned int bgr:1; + } link; /* 36 bytes */ + } u; + /* 0 or 4 bytes padding */ +} fz_store_hash; /* 40 or 48 bytes */ + +/** + Every type of object to be placed into the store defines an + fz_store_type. This contains the pointers to functions to + make hashes, manipulate keys, and check for needing reaping. +*/ +typedef struct +{ + const char *name; + int (*make_hash_key)(fz_context *ctx, fz_store_hash *hash, void *key); + void *(*keep_key)(fz_context *ctx, void *key); + void (*drop_key)(fz_context *ctx, void *key); + int (*cmp_key)(fz_context *ctx, void *a, void *b); + void (*format_key)(fz_context *ctx, char *buf, size_t size, void *key); + int (*needs_reap)(fz_context *ctx, void *key); +} fz_store_type; + +/** + Create a new store inside the context + + max: The maximum size (in bytes) that the store is allowed to + grow to. FZ_STORE_UNLIMITED means no limit. +*/ +void fz_new_store_context(fz_context *ctx, size_t max); + +/** + Increment the reference count for the store context. Returns + the same pointer. + + Never throws exceptions. +*/ +fz_store *fz_keep_store_context(fz_context *ctx); + +/** + Decrement the reference count for the store context. When the + reference count hits zero, the store context is freed. + + Never throws exceptions. +*/ +void fz_drop_store_context(fz_context *ctx); + +/** + Add an item to the store. + + Add an item into the store, returning NULL for success. If an + item with the same key is found in the store, then our item will + not be inserted, and the function will return a pointer to that + value instead. This function takes its own reference to val, as + required (i.e. the caller maintains ownership of its own + reference). + + key: The key used to index the item. + + val: The value to store. + + itemsize: The size in bytes of the value (as counted towards the + store size). + + type: Functions used to manipulate the key. +*/ +void *fz_store_item(fz_context *ctx, void *key, void *val, size_t itemsize, const fz_store_type *type); + +/** + Find an item within the store. + + drop: The function used to free the value (to ensure we get a + value of the correct type). + + key: The key used to index the item. + + type: Functions used to manipulate the key. + + Returns NULL for not found, otherwise returns a pointer to the + value indexed by key to which a reference has been taken. +*/ +void *fz_find_item(fz_context *ctx, fz_store_drop_fn *drop, void *key, const fz_store_type *type); + +/** + Remove an item from the store. + + If an item indexed by the given key exists in the store, remove + it. + + drop: The function used to free the value (to ensure we get a + value of the correct type). + + key: The key used to find the item to remove. + + type: Functions used to manipulate the key. +*/ +void fz_remove_item(fz_context *ctx, fz_store_drop_fn *drop, void *key, const fz_store_type *type); + +/** + Evict every item from the store. +*/ +void fz_empty_store(fz_context *ctx); + +/** + Internal function used as part of the scavenging + allocator; when we fail to allocate memory, before returning a + failure to the caller, we try to scavenge space within the store + by evicting at least 'size' bytes. The allocator then retries. + + size: The number of bytes we are trying to have free. + + phase: What phase of the scavenge we are in. Updated on exit. + + Returns non zero if we managed to free any memory. +*/ +int fz_store_scavenge(fz_context *ctx, size_t size, int *phase); + +/** + External function for callers to use + to scavenge while trying allocations. + + size: The number of bytes we are trying to have free. + + phase: What phase of the scavenge we are in. Updated on exit. + + Returns non zero if we managed to free any memory. +*/ +int fz_store_scavenge_external(fz_context *ctx, size_t size, int *phase); + +/** + Evict items from the store until the total size of + the objects in the store is reduced to a given percentage of its + current size. + + percent: %age of current size to reduce the store to. + + Returns non zero if we managed to free enough memory, zero + otherwise. +*/ +int fz_shrink_store(fz_context *ctx, unsigned int percent); + +/** + Callback function called by fz_filter_store on every item within + the store. + + Return 1 to drop the item from the store, 0 to retain. +*/ +typedef int (fz_store_filter_fn)(fz_context *ctx, void *arg, void *key); + +/** + Filter every element in the store with a matching type with the + given function. + + If the function returns 1 for an element, drop the element. +*/ +void fz_filter_store(fz_context *ctx, fz_store_filter_fn *fn, void *arg, const fz_store_type *type); + +/** + Filter the store and throw away any stored tiles drawn for a + given document. +*/ +void fz_drop_drawn_tiles_for_document(fz_context *ctx, fz_document *doc); + +/** + Output debugging information for the current state of the store + to the given output channel. +*/ +void fz_debug_store(fz_context *ctx, fz_output *out); + +/** + Increment the defer reap count. + + No reap operations will take place (except for those + triggered by an immediate failed malloc) until the + defer reap count returns to 0. + + Call this at the start of a process during which you + potentially might drop many reapable objects. + + It is vital that every fz_defer_reap_start is matched + by a fz_defer_reap_end call. +*/ +void fz_defer_reap_start(fz_context *ctx); + +/** + Decrement the defer reap count. + + If the defer reap count returns to 0, and the store + has reapable objects in, a reap pass will begin. + + Call this at the end of a process during which you + potentially might drop many reapable objects. + + It is vital that every fz_defer_reap_start is matched + by a fz_defer_reap_end call. +*/ +void fz_defer_reap_end(fz_context *ctx); + +#ifdef ENABLE_STORE_LOGGING + +void fz_log_dump_store(fz_context *ctx, const char *fmt, ...); + +#define FZ_LOG_STORE(CTX, ...) fz_log_module(CTX, "STORE", __VA_ARGS__) +#define FZ_LOG_DUMP_STORE(...) fz_log_dump_store(__VA_ARGS__) + +#else + +#define FZ_LOG_STORE(...) do {} while (0) +#define FZ_LOG_DUMP_STORE(...) do {} while (0) + +#endif + +#endif
