diff options
-rw-r--r-- | apps/pdfapp.c | 6 | ||||
-rw-r--r-- | apps/pdfclean.c | 2 | ||||
-rw-r--r-- | apps/pdfdraw.c | 4 | ||||
-rw-r--r-- | apps/pdfextract.c | 2 | ||||
-rw-r--r-- | apps/pdfshow.c | 2 | ||||
-rw-r--r-- | apps/win_main.c | 2 | ||||
-rw-r--r-- | apps/xpsdraw.c | 2 | ||||
-rw-r--r-- | fitz/base_context.c | 6 | ||||
-rw-r--r-- | fitz/fitz.h | 51 | ||||
-rw-r--r-- | fitz/res_colorspace.c | 35 | ||||
-rw-r--r-- | fitz/res_pixmap.c | 58 | ||||
-rw-r--r-- | fitz/res_shade.c | 22 | ||||
-rw-r--r-- | fitz/res_store.c | 364 | ||||
-rw-r--r-- | pdf/mupdf.h | 32 | ||||
-rw-r--r-- | pdf/pdf_cmap.c | 31 | ||||
-rw-r--r-- | pdf/pdf_cmap_load.c | 20 | ||||
-rw-r--r-- | pdf/pdf_colorspace.c | 10 | ||||
-rw-r--r-- | pdf/pdf_font.c | 54 | ||||
-rw-r--r-- | pdf/pdf_function.c | 69 | ||||
-rw-r--r-- | pdf/pdf_image.c | 6 | ||||
-rw-r--r-- | pdf/pdf_metrics.c | 2 | ||||
-rw-r--r-- | pdf/pdf_page.c | 4 | ||||
-rw-r--r-- | pdf/pdf_pattern.c | 60 | ||||
-rw-r--r-- | pdf/pdf_shade.c | 16 | ||||
-rw-r--r-- | pdf/pdf_store.c | 224 | ||||
-rw-r--r-- | pdf/pdf_type3.c | 3 | ||||
-rw-r--r-- | pdf/pdf_unicode.c | 2 | ||||
-rw-r--r-- | pdf/pdf_xobject.c | 64 | ||||
-rw-r--r-- | pdf/pdf_xref.c | 3 | ||||
-rw-r--r-- | scripts/cmapdump.c | 21 | ||||
-rw-r--r-- | win32/libmupdf.vcproj | 8 | ||||
-rw-r--r-- | xps/xps_gradient.c | 4 |
32 files changed, 727 insertions, 462 deletions
diff --git a/apps/pdfapp.c b/apps/pdfapp.c index 9893af39..c1e026fe 100644 --- a/apps/pdfapp.c +++ b/apps/pdfapp.c @@ -259,10 +259,6 @@ void pdfapp_close(pdfapp_t *app) if (app->xref) { - if (app->xref->store) - pdf_free_store(app->ctx, app->xref->store); - app->xref->store = NULL; - pdf_free_xref(app->xref); app->xref = NULL; } @@ -347,7 +343,7 @@ static void pdfapp_loadpage_pdf(pdfapp_t *app) pdf_free_page(app->ctx, page); - pdf_age_store(app->ctx, app->xref->store, 3); + fz_age_store(app->ctx, 3); } static void pdfapp_loadpage_xps(pdfapp_t *app) diff --git a/apps/pdfclean.c b/apps/pdfclean.c index e13ad0f6..e8c27359 100644 --- a/apps/pdfclean.c +++ b/apps/pdfclean.c @@ -767,7 +767,7 @@ int main(int argc, char **argv) if (argc - fz_optind > 0) subset = 1; - ctx = fz_new_context(&fz_alloc_default); + ctx = fz_new_context(&fz_alloc_default, FZ_STORE_UNLIMITED); if (!ctx) { fprintf(stderr, "cannot initialise context\n"); diff --git a/apps/pdfdraw.c b/apps/pdfdraw.c index 861d2b3f..af1d5ad7 100644 --- a/apps/pdfdraw.c +++ b/apps/pdfdraw.c @@ -263,7 +263,7 @@ static void drawpage(pdf_xref *xref, int pagenum) if (showmd5 || showtime) printf("\n"); - pdf_age_store(ctx, xref->store, 3); + fz_age_store(ctx, 3); fz_flush_warnings(ctx); } @@ -362,7 +362,7 @@ int main(int argc, char **argv) if (accelerate) fz_accelerate(); - ctx = fz_new_context(&fz_alloc_default); + ctx = fz_new_context(&fz_alloc_default, FZ_STORE_UNLIMITED); if (!ctx) { fprintf(stderr, "cannot initialise context\n"); diff --git a/apps/pdfextract.c b/apps/pdfextract.c index c32a25c5..590bf13f 100644 --- a/apps/pdfextract.c +++ b/apps/pdfextract.c @@ -178,7 +178,7 @@ int main(int argc, char **argv) infile = argv[fz_optind++]; - ctx = fz_new_context(&fz_alloc_default); + ctx = fz_new_context(&fz_alloc_default, FZ_STORE_UNLIMITED); if (!ctx) { fprintf(stderr, "cannot initialise context\n"); diff --git a/apps/pdfshow.c b/apps/pdfshow.c index c437f262..0c3feaf2 100644 --- a/apps/pdfshow.c +++ b/apps/pdfshow.c @@ -189,7 +189,7 @@ int main(int argc, char **argv) filename = argv[fz_optind++]; - ctx = fz_new_context(&fz_alloc_default); + ctx = fz_new_context(&fz_alloc_default, FZ_STORE_UNLIMITED); if (!ctx) { fprintf(stderr, "cannot initialise context\n"); diff --git a/apps/win_main.c b/apps/win_main.c index eb0e6085..0af83aec 100644 --- a/apps/win_main.c +++ b/apps/win_main.c @@ -831,7 +831,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShow fz_accelerate(); - ctx = fz_new_context(&fz_alloc_default); + ctx = fz_new_context(&fz_alloc_default, FZ_STORE_UNLIMITED); if (!ctx) { fprintf(stderr, "cannot initialise context\n"); diff --git a/apps/xpsdraw.c b/apps/xpsdraw.c index a7223574..f583057e 100644 --- a/apps/xpsdraw.c +++ b/apps/xpsdraw.c @@ -314,7 +314,7 @@ int main(int argc, char **argv) if (accelerate) fz_accelerate(); - ctx = fz_new_context(&fz_alloc_default); + ctx = fz_new_context(&fz_alloc_default, FZ_STORE_UNLIMITED); if (!ctx) { fprintf(stderr, "cannot initialise context\n"); diff --git a/fitz/base_context.c b/fitz/base_context.c index 3d9df6aa..e722aa1d 100644 --- a/fitz/base_context.c +++ b/fitz/base_context.c @@ -15,6 +15,7 @@ fz_free_context(fz_context *ctx) return; /* Other finalisation calls go here (in reverse order) */ + fz_free_store_context(ctx); fz_free_aa_context(ctx); fz_free_font_context(ctx); @@ -30,7 +31,7 @@ fz_free_context(fz_context *ctx) } fz_context * -fz_new_context(fz_alloc_context *alloc) +fz_new_context(fz_alloc_context *alloc, unsigned int max_store) { fz_context *ctx; @@ -57,6 +58,7 @@ fz_new_context(fz_alloc_context *alloc) { fz_new_font_context(ctx); fz_new_aa_context(ctx); + fz_new_store_context(ctx, max_store); } fz_catch(ctx) { @@ -74,5 +76,5 @@ cleanup: fz_context * fz_clone_context(fz_context *ctx) { - return fz_new_context(ctx->alloc); + return fz_new_context(ctx->alloc, FZ_STORE_UNLIMITED); } diff --git a/fitz/fitz.h b/fitz/fitz.h index 8d523e3f..ebbd176c 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -100,6 +100,7 @@ typedef struct fz_error_context_s fz_error_context; typedef struct fz_warn_context_s fz_warn_context; typedef struct fz_font_context_s fz_font_context; typedef struct fz_aa_context_s fz_aa_context; +typedef struct fz_store_s fz_store; typedef struct fz_context_s fz_context; struct fz_alloc_context_s @@ -156,9 +157,10 @@ struct fz_context_s fz_warn_context *warn; fz_font_context *font; fz_aa_context *aa; + fz_store *store; }; -fz_context *fz_new_context(fz_alloc_context *alloc); +fz_context *fz_new_context(fz_alloc_context *alloc, unsigned int max_store); fz_context *fz_clone_context(fz_context *ctx); void fz_free_context(fz_context *ctx); @@ -490,6 +492,42 @@ void fz_resize_buffer(fz_context *ctx, fz_buffer *buf, int size); void fz_grow_buffer(fz_context *ctx, fz_buffer *buf); /* + * Resource store + */ + +typedef struct fz_storable_s fz_storable; + +typedef struct fz_item_s fz_item; + +typedef void (fz_store_free_fn)(fz_context *, void *); + +struct fz_storable_s { + int refs; + fz_store_free_fn *free; +}; + +#define FZ_INIT_STORABLE(S_,RC,FREE) \ + do { fz_storable *S = &(S_)->storable; S->refs = (RC); \ + S->free = (FREE); \ + } while (0) + +enum { + FZ_STORE_UNLIMITED = 0 +}; + +void fz_new_store_context(fz_context *ctx, unsigned int max); +void fz_free_store_context(fz_context *ctx); +void fz_debug_store(fz_context *ctx); + +void *fz_keep_storable(fz_storable *); +void fz_drop_storable(fz_context *, fz_storable *); + +void fz_store_item(fz_context *ctx, fz_obj *key, void *val, unsigned int itemsize); +void *fz_find_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key); +void fz_remove_item(fz_context *ctx, fz_store_free_fn *freefn, fz_obj *key); +void fz_age_store(fz_context *ctx, int maxage); + +/* * Buffered reader. * Only the data between rp and wp is valid data. */ @@ -648,7 +686,7 @@ typedef struct fz_colorspace_s fz_colorspace; struct fz_pixmap_s { - int refs; + fz_storable storable; int x, y, w, h, n; fz_pixmap *mask; /* explicit soft/image mask */ int interpolate; @@ -667,6 +705,7 @@ fz_pixmap *fz_new_pixmap_with_rect_and_data(fz_context *ctx, fz_colorspace *, fz fz_pixmap *fz_new_pixmap(fz_context *ctx, fz_colorspace *, int w, int h); fz_pixmap *fz_keep_pixmap(fz_pixmap *pix); void fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix); +void fz_free_pixmap_imp(fz_context *ctx, void *pix); void fz_clear_pixmap(fz_pixmap *pix); void fz_clear_pixmap_with_color(fz_pixmap *pix, int value); void fz_clear_pixmap_rect_with_color(fz_pixmap *pix, int value, fz_bbox r); @@ -677,6 +716,7 @@ fz_pixmap *fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray, int luminosity); fz_bbox fz_bound_pixmap(fz_pixmap *pix); void fz_invert_pixmap(fz_pixmap *pix); void fz_gamma_pixmap(fz_pixmap *pix, float gamma); +unsigned int fz_pixmap_size(fz_pixmap *pix); fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h); @@ -740,7 +780,8 @@ extern fz_colorspace *fz_device_cmyk; struct fz_colorspace_s { - int refs; + fz_storable storable; + unsigned int size; char name[16]; int n; void (*to_rgb)(fz_context *ctx, fz_colorspace *, float *src, float *rgb); @@ -752,6 +793,7 @@ struct fz_colorspace_s fz_colorspace *fz_new_colorspace(fz_context *ctx, char *name, int n); fz_colorspace *fz_keep_colorspace(fz_colorspace *colorspace); void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace); +void fz_free_colorspace_imp(fz_context *ctx, void *colorspace); void fz_convert_color(fz_context *ctx, fz_colorspace *srcs, float *srcv, fz_colorspace *dsts, float *dstv); void fz_convert_pixmap(fz_context *ctx, fz_pixmap *src, fz_pixmap *dst); @@ -928,7 +970,7 @@ typedef struct fz_shade_s fz_shade; struct fz_shade_s { - int refs; + fz_storable storable; fz_rect bbox; /* can be fz_infinite_rect */ fz_colorspace *colorspace; @@ -950,6 +992,7 @@ struct fz_shade_s fz_shade *fz_keep_shade(fz_shade *shade); void fz_drop_shade(fz_context *ctx, fz_shade *shade); +void fz_free_shade_imp(fz_context *ctx, void *shade); void fz_debug_shade(fz_shade *shade); fz_rect fz_bound_shade(fz_shade *shade, fz_matrix ctm); diff --git a/fitz/res_colorspace.c b/fitz/res_colorspace.c index 85556b62..8f145658 100644 --- a/fitz/res_colorspace.c +++ b/fitz/res_colorspace.c @@ -2,11 +2,22 @@ #define SLOWCMYK +void +fz_free_colorspace_imp(fz_context *ctx, void *cs_) +{ + fz_colorspace *cs = (fz_colorspace *)cs_; + + if (cs->free_data && cs->data) + cs->free_data(ctx, cs); + fz_free(ctx, cs); +} + fz_colorspace * fz_new_colorspace(fz_context *ctx, char *name, int n) { fz_colorspace *cs = fz_malloc(ctx, sizeof(fz_colorspace)); - cs->refs = 1; + FZ_INIT_STORABLE(cs, 1, fz_free_colorspace_imp); + cs->size = sizeof(fz_colorspace); fz_strlcpy(cs->name, name, sizeof cs->name); cs->n = n; cs->to_rgb = NULL; @@ -19,23 +30,13 @@ fz_new_colorspace(fz_context *ctx, char *name, int n) fz_colorspace * fz_keep_colorspace(fz_colorspace *cs) { - if (cs->refs < 0) - return cs; - cs->refs ++; - return cs; + return (fz_colorspace *)fz_keep_storable(&cs->storable); } void fz_drop_colorspace(fz_context *ctx, fz_colorspace *cs) { - if (cs && cs->refs < 0) - return; - if (cs && --cs->refs == 0) - { - if (cs->free_data && cs->data) - cs->free_data(ctx, cs); - fz_free(ctx, cs); - } + fz_drop_storable(ctx, &cs->storable); } /* Device colorspace definitions */ @@ -152,10 +153,10 @@ static void rgb_to_cmyk(fz_context *ctx, fz_colorspace *cs, float *rgb, float *c cmyk[3] = k; } -static fz_colorspace k_device_gray = { -1, "DeviceGray", 1, gray_to_rgb, rgb_to_gray }; -static fz_colorspace k_device_rgb = { -1, "DeviceRGB", 3, rgb_to_rgb, rgb_to_rgb }; -static fz_colorspace k_device_bgr = { -1, "DeviceRGB", 3, bgr_to_rgb, rgb_to_bgr }; -static fz_colorspace k_device_cmyk = { -1, "DeviceCMYK", 4, cmyk_to_rgb, rgb_to_cmyk }; +static fz_colorspace k_device_gray = { {-1, fz_free_colorspace_imp}, 0, "DeviceGray", 1, gray_to_rgb, rgb_to_gray }; +static fz_colorspace k_device_rgb = { {-1, fz_free_colorspace_imp}, 0, "DeviceRGB", 3, rgb_to_rgb, rgb_to_rgb }; +static fz_colorspace k_device_bgr = { {-1, fz_free_colorspace_imp}, 0, "DeviceRGB", 3, bgr_to_rgb, rgb_to_bgr }; +static fz_colorspace k_device_cmyk = { {-1, fz_free_colorspace_imp}, 0, "DeviceCMYK", 4, cmyk_to_rgb, rgb_to_cmyk }; fz_colorspace *fz_device_gray = &k_device_gray; fz_colorspace *fz_device_rgb = &k_device_rgb; diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c index 1dfc8ad0..c8ae7540 100644 --- a/fitz/res_pixmap.c +++ b/fitz/res_pixmap.c @@ -4,12 +4,37 @@ static int fz_memory_limit = 256 << 20; static int fz_memory_used = 0; fz_pixmap * +fz_keep_pixmap(fz_pixmap *pix) +{ + return (fz_pixmap *)fz_keep_storable(&pix->storable); +} + +void +fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix) +{ + fz_drop_storable(ctx, &pix->storable); +} + +void +fz_free_pixmap_imp(fz_context *ctx, fz_pixmap *pix) +{ + fz_memory_used -= pix->w * pix->h * pix->n; + if (pix->mask) + fz_drop_pixmap(ctx, pix->mask); + if (pix->colorspace) + fz_drop_colorspace(ctx, pix->colorspace); + if (pix->free_samples) + fz_free(ctx, pix->samples); + fz_free(ctx, pix); +} + +fz_pixmap * fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, unsigned char *samples) { fz_pixmap *pix; pix = fz_malloc(ctx, sizeof(fz_pixmap)); - pix->refs = 1; + FZ_INIT_STORABLE(pix, 1, fz_free_pixmap_imp); pix->x = 0; pix->y = 0; pix->w = w; @@ -82,29 +107,6 @@ fz_new_pixmap_with_rect_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_ return pixmap; } -fz_pixmap * -fz_keep_pixmap(fz_pixmap *pix) -{ - pix->refs++; - return pix; -} - -void -fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix) -{ - if (pix && --pix->refs == 0) - { - fz_memory_used -= pix->w * pix->h * pix->n; - if (pix->mask) - fz_drop_pixmap(ctx, pix->mask); - if (pix->colorspace) - fz_drop_colorspace(ctx, pix->colorspace); - if (pix->free_samples) - fz_free(ctx, pix->samples); - fz_free(ctx, pix); - } -} - fz_bbox fz_bound_pixmap(fz_pixmap *pix) { @@ -533,3 +535,11 @@ fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha) fz_free(ctx, udata); fz_free(ctx, cdata); } + +unsigned int +fz_pixmap_size(fz_pixmap * pix) +{ + if (pix == NULL) + return 0; + return sizeof(*pix) + pix->n * pix->x * pix->y; +} diff --git a/fitz/res_shade.c b/fitz/res_shade.c index b7617161..c2a8c858 100644 --- a/fitz/res_shade.c +++ b/fitz/res_shade.c @@ -3,20 +3,24 @@ fz_shade * fz_keep_shade(fz_shade *shade) { - shade->refs ++; - return shade; + return (fz_shade *)fz_keep_storable(&shade->storable); +} + +void +fz_free_shade_imp(fz_context *ctx, void *shade_) +{ + fz_shade *shade = (fz_shade *)shade_; + + if (shade->colorspace) + fz_drop_colorspace(ctx, shade->colorspace); + fz_free(ctx, shade->mesh); + fz_free(ctx, shade); } void fz_drop_shade(fz_context *ctx, fz_shade *shade) { - if (shade && --shade->refs == 0) - { - if (shade->colorspace) - fz_drop_colorspace(ctx, shade->colorspace); - fz_free(ctx, shade->mesh); - fz_free(ctx, shade); - } + fz_drop_storable(ctx, &shade->storable); } fz_rect diff --git a/fitz/res_store.c b/fitz/res_store.c new file mode 100644 index 00000000..08885c30 --- /dev/null +++ b/fitz/res_store.c @@ -0,0 +1,364 @@ +#include "fitz.h" +#include "mupdf.h" + +struct fz_item_s +{ + fz_obj *key; + fz_storable *val; + unsigned int size; + fz_item *next; + fz_item *prev; + fz_store *store; + int age; +}; + +struct refkey +{ + fz_store_free_fn *free; + int num; + int gen; +}; + +struct fz_store_s +{ + /* Every item in the store is kept in a doubly linked list, ordered + * by usage (so LRU entries are at the end). */ + fz_item *head; + fz_item *tail; + + /* We have a hash table that allows to quickly find a subset of the + * entries (those whose keys are indirect objects). */ + fz_hash_table *hash; + + /* We keep track of the size of the store, and keep it below max. */ + unsigned int max; + unsigned int size; +}; + +void +fz_new_store_context(fz_context *ctx, unsigned int max) +{ + fz_store *store; + store = fz_malloc(ctx, sizeof(fz_store)); + store->hash = fz_new_hash_table(ctx, 4096, sizeof(struct refkey)); + store->head = NULL; + store->tail = NULL; + store->size = 0; + store->max = max; + ctx->store = store; +} + +void * +fz_keep_storable(fz_storable *s) +{ + if (s == NULL) + return NULL; + /* LOCK */ + if (s->refs > 0) + s->refs++; + /* UNLOCK */ + return s; +} + +void +fz_drop_storable(fz_context *ctx, fz_storable *s) +{ + if (s == NULL) + return; + /* LOCK */ + if (s->refs < 0) + { + /* It's a static object. Dropping does nothing. */ + } + else if (--s->refs == 0) + { + /* If we are dropping the last reference to an object, then + * it cannot possibly be in the store (as the store always + * keeps a ref to everything in it, and doesn't drop via + * this method. So we can simply drop the storable object + * itself without any operations on the fz_store. */ + s->free(ctx, s); + } + /* UNLOCK */ +} + +static void +evict(fz_context *ctx, fz_store *store, fz_item *item) +{ + store->size -= item->size; + /* Unlink from the linked list */ + if (item->next) + item->next->prev = item->prev; + else + store->tail = item->prev; + if (item->prev) + item->prev->next = item->next; + else + store->head = item->next; + /* Remove from the hash table */ + if (fz_is_indirect(item->key)) + { + struct refkey refkey; + refkey.free = item->val->free; + refkey.num = fz_to_num(item->key); + refkey.gen = fz_to_gen(item->key); + fz_hash_remove(store->hash, &refkey); + } + /* Drop the value, key and item */ + item->val->free(ctx, item->val); + fz_drop_obj(item->key); + fz_free(ctx, item); +} + +static int +ensure_space(fz_context *ctx, unsigned int tofree) +{ + fz_item *item, *prev; + unsigned int count; + fz_store *store = ctx->store; + + /* First check that we *can* free tofree; if not, we'd rather not + * cache this. */ + count = 0; + for (item = store->tail; item; item = item->prev) + { + if (item->val->refs == 1) + { + count += item->size; + if (count >= tofree) + break; + } + } + + /* If we ran out of items to search, then we can never free enough */ + if (item == NULL) + return 1; + + /* Actually free the items */ + count = 0; + for (item = store->tail; item; item = prev) + { + prev = item->prev; + if (item->val->refs == 1) + { + /* Free this item */ + count += item->size; + evict(ctx, store, item); + + if (count >= tofree) + break; + } + } + + return 0; +} + +void +fz_store_item(fz_context *ctx, fz_obj *key, void *val_, unsigned int itemsize) +{ + fz_item *item; + unsigned int size; + fz_storable *val = (fz_storable *)val_; + fz_store *store = ctx->store; + + if (!store) + return; + + item = fz_malloc(ctx, sizeof(*item)); + /* LOCK */ + size = store->size + itemsize; + if (store->max != FZ_STORE_UNLIMITED && size > store->max && ensure_space(ctx, size - store->max)) + { + fz_free(ctx, item); + /* UNLOCK */ + return; + } + store->size += itemsize; + + item->key = fz_keep_obj(key); + item->val = val; + item->size = itemsize; + item->next = NULL; + if (val->refs > 0) + val->refs++; + + /* If we can index it fast, put it into the hash table */ + if (fz_is_indirect(key)) + { + struct refkey refkey; + refkey.free = val->free; + refkey.num = fz_to_num(key); + refkey.gen = fz_to_gen(key); + fz_hash_insert(store->hash, &refkey, item); + } + /* Regardless of whether it's indexed, it goes into the linked list */ + item->next = store->head; + if (item->next) + item->next->prev = item; + else + store->tail = item; + store->head = item; + item->prev = NULL; + /* UNLOCK */ +} + +void * +fz_find_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) +{ + struct refkey refkey; + fz_item *item; + fz_store *store = ctx->store; + + if (!store) + return NULL; + + if (!key) + return NULL; + + /* LOCK */ + if (fz_is_indirect(key)) + { + /* We can find objects keyed on indirected objects quickly */ + refkey.free = free; + refkey.num = fz_to_num(key); + refkey.gen = fz_to_gen(key); + item = fz_hash_find(store->hash, &refkey); + } + else + { + /* Others we have to hunt for slowly */ + for (item = store->head; item; item = item->next) + { + if (item->val->free == free && !fz_objcmp(item->key, key)) + break; + } + } + if (item) + { + /* LRU: Move the block to the front */ + /* Unlink from present position */ + if (item->next) + item->next->prev = item->prev; + else + store->tail = item->prev; + if (item->prev) + item->prev->next = item->next; + else + store->head = item->next; + /* Insert at head */ + item->next = store->head; + if (item->next) + item->next->prev = item; + else + store->tail = item; + item->prev = NULL; + store->head = item; + /* And bump the refcount before returning */ + if (item->val->refs > 0) + item->val->refs++; + /* UNLOCK */ + return (void *)item->val; + } + /* UNLOCK */ + + return NULL; +} + +void +fz_remove_item(fz_context *ctx, fz_store_free_fn *free, fz_obj *key) +{ + struct refkey refkey; + fz_item *item; + fz_store *store = ctx->store; + + /* LOCK */ + if (fz_is_indirect(key)) + { + /* We can find objects keyed on indirect objects quickly */ + refkey.free = free; + refkey.num = fz_to_num(key); + refkey.gen = fz_to_gen(key); + item = fz_hash_find(store->hash, &refkey); + if (item) + fz_hash_remove(store->hash, &refkey); + } + else + { + /* Others we have to hunt for slowly */ + for (item = store->head; item; item = item->next) + if (item->val->free == free && !fz_objcmp(item->key, key)) + break; + } + if (item) + { + if (item->next) + item->next->prev = item->prev; + else + store->tail = item->prev; + if (item->prev) + item->prev->next = item->next; + else + store->head = item->next; + if (item->val->refs > 0 && --item->val->refs == 0) + item->val->free(ctx, item->val); + fz_drop_obj(item->key); + fz_free(ctx, item); + } + /* UNLOCK */ +} + +void +fz_age_store(fz_context *ctx, int maxage) +{ + fz_item *item, *next; + fz_store *store = ctx->store; + + if (store == NULL) + return; + + /* LOCK */ + /* Run through all the items in the store */ + for (item = store->head; item; item = next) + { + next = item->next; + /* If we've only got 1 reference, then we must be the only + * holders. Age the item. If it's older than the maximum, + * bin it. */ + if (item->val->refs == 1 && ++item->age > maxage) + evict(ctx, store, item); + } + /* UNLOCK */ +} + +void +fz_free_store_context(fz_context *ctx) +{ + if (ctx == NULL || ctx->store == NULL) + return; + fz_age_store(ctx, 0); + fz_free_hash(ctx->store->hash); + fz_free(ctx, ctx->store); + ctx->store = NULL; +} + +void +fz_debug_store(fz_context *ctx) +{ + fz_item *item; + fz_store *store = ctx->store; + + printf("-- resource store contents --\n"); + + /* LOCK */ + for (item = store->head; item; item = item->next) + { + printf("store[*][claim=%d] ", item->val->refs); + if (fz_is_indirect(item->key)) + { + printf("(%d %d R) ", fz_to_num(item->key), fz_to_gen(item->key)); + } else + fz_debug_obj(item->key); + printf(" = %p\n", item->val); + } + /* UNLOCK */ +} diff --git a/pdf/mupdf.h b/pdf/mupdf.h index 79560dab..890e9f8b 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -90,8 +90,6 @@ struct pdf_xref_s fz_obj **page_objs; fz_obj **page_refs; - struct pdf_store_s *store; - char scratch[65536]; }; @@ -154,24 +152,6 @@ unsigned char *pdf_get_crypt_key(pdf_xref *xref); void pdf_debug_crypt(pdf_crypt *crypt); /* - * Resource store - */ - -typedef struct pdf_store_s pdf_store; - -pdf_store *pdf_new_store(fz_context *ctx); -void pdf_free_store(fz_context *ctx, pdf_store *store); -void pdf_debug_store(fz_context *ctx, pdf_store *store); - -typedef void *(pdf_store_keep_fn)(void *); -typedef void (pdf_store_drop_fn)(fz_context *, void *); - -void pdf_store_item(fz_context *ctx, pdf_store *store, pdf_store_keep_fn *keepfn, pdf_store_drop_fn *dropfn, fz_obj *key, void *val); -void *pdf_find_item(fz_context *ctx, pdf_store *store, pdf_store_drop_fn *dropfn, fz_obj *key); -void pdf_remove_item(fz_context *ctx, pdf_store *store, pdf_store_drop_fn *dropfn, fz_obj *key); -void pdf_age_store(fz_context *ctx, pdf_store *store, int maxage); - -/* * Functions, Colorspaces, Shadings and Images */ @@ -181,6 +161,7 @@ pdf_function *pdf_load_function(pdf_xref *xref, fz_obj *ref); void pdf_eval_function(fz_context *ctx, pdf_function *func, float *in, int inlen, float *out, int outlen); pdf_function *pdf_keep_function(pdf_function *func); void pdf_drop_function(fz_context *ctx, pdf_function *func); +unsigned int pdf_function_size(pdf_function *func); fz_colorspace *pdf_load_colorspace(pdf_xref *xref, fz_obj *obj); fz_pixmap *pdf_expand_indexed_pixmap(fz_context *ctx, fz_pixmap *src); @@ -199,7 +180,7 @@ typedef struct pdf_pattern_s pdf_pattern; struct pdf_pattern_s { - int refs; + fz_storable storable; int ismask; float xstep; float ystep; @@ -221,7 +202,7 @@ typedef struct pdf_xobject_s pdf_xobject; struct pdf_xobject_s { - int refs; + fz_storable storable; fz_matrix matrix; fz_rect bbox; int isolated; @@ -257,7 +238,7 @@ struct pdf_range_s struct pdf_cmap_s { - int refs; + fz_storable storable; char cmap_name[32]; char usecmap_name[32]; @@ -283,6 +264,8 @@ struct pdf_cmap_s pdf_cmap *pdf_new_cmap(fz_context *ctx); pdf_cmap *pdf_keep_cmap(pdf_cmap *cmap); void pdf_drop_cmap(fz_context *ctx, pdf_cmap *cmap); +void pdf_free_cmap_imp(fz_context *ctx, void *cmap); +unsigned int pdf_cmap_size(pdf_cmap *cmap); void pdf_debug_cmap(pdf_cmap *cmap); int pdf_get_wmode(pdf_cmap *cmap); @@ -356,7 +339,8 @@ struct pdf_vmtx_s struct pdf_font_desc_s { - int refs; + fz_storable storable; + unsigned int size; fz_font *font; diff --git a/pdf/pdf_cmap.c b/pdf/pdf_cmap.c index 8ae40fc5..b92f616e 100644 --- a/pdf/pdf_cmap.c +++ b/pdf/pdf_cmap.c @@ -30,13 +30,24 @@ * Allocate, destroy and simple parameters. */ +void +pdf_free_cmap_imp(fz_context *ctx, void *cmap_) +{ + pdf_cmap *cmap = (pdf_cmap *)cmap_; + if (cmap->usecmap) + pdf_drop_cmap(ctx, cmap->usecmap); + fz_free(ctx, cmap->ranges); + fz_free(ctx, cmap->table); + fz_free(ctx, cmap); +} + pdf_cmap * pdf_new_cmap(fz_context *ctx) { pdf_cmap *cmap; cmap = fz_malloc(ctx, sizeof(pdf_cmap)); - cmap->refs = 1; + FZ_INIT_STORABLE(cmap, 1, pdf_free_cmap_imp); strcpy(cmap->cmap_name, ""); strcpy(cmap->usecmap_name, ""); @@ -55,28 +66,18 @@ pdf_new_cmap(fz_context *ctx) return cmap; } +/* Could be a macro for speed */ pdf_cmap * pdf_keep_cmap(pdf_cmap *cmap) { - if (cmap->refs >= 0) - cmap->refs ++; - return cmap; + return (pdf_cmap *)fz_keep_storable(&cmap->storable); } +/* Could be a macro for speed */ void pdf_drop_cmap(fz_context *ctx, pdf_cmap *cmap) { - if (cmap->refs >= 0) - { - if (--cmap->refs == 0) - { - if (cmap->usecmap) - pdf_drop_cmap(ctx, cmap->usecmap); - fz_free(ctx, cmap->ranges); - fz_free(ctx, cmap->table); - fz_free(ctx, cmap); - } - } + fz_drop_storable(ctx, &cmap->storable); } void diff --git a/pdf/pdf_cmap_load.c b/pdf/pdf_cmap_load.c index 5bcf578f..51949907 100644 --- a/pdf/pdf_cmap_load.c +++ b/pdf/pdf_cmap_load.c @@ -1,6 +1,17 @@ #include "fitz.h" #include "mupdf.h" +unsigned int +pdf_cmap_size(pdf_cmap *cmap) +{ + if (cmap == NULL) + return 0; + if (cmap->storable.refs < 0) + return 0; + + return cmap->rcap * sizeof(pdf_range) + cmap->tcap * sizeof(short) + pdf_cmap_size(cmap->usecmap); +} + /* * Load CMap stream in PDF file */ @@ -13,11 +24,12 @@ pdf_load_embedded_cmap(pdf_xref *xref, fz_obj *stmobj) fz_obj *wmode; fz_obj *obj; fz_context *ctx = xref->ctx; - volatile int phase = 0; + int phase = 0; + + fz_var(phase); - if ((cmap = pdf_find_item(ctx, xref->store, (pdf_store_drop_fn *)pdf_drop_cmap, stmobj))) + if ((cmap = fz_find_item(ctx, pdf_free_cmap_imp, stmobj))) { - pdf_keep_cmap(cmap); return cmap; } @@ -49,7 +61,7 @@ pdf_load_embedded_cmap(pdf_xref *xref, fz_obj *stmobj) pdf_drop_cmap(ctx, usecmap); } - pdf_store_item(ctx, xref->store, (pdf_store_keep_fn *)pdf_keep_cmap, (pdf_store_drop_fn *)pdf_drop_cmap, stmobj, cmap); + fz_store_item(ctx, stmobj, cmap, pdf_cmap_size(cmap)); } fz_catch(ctx) { diff --git a/pdf/pdf_colorspace.c b/pdf/pdf_colorspace.c index c386b34c..9edc1e90 100644 --- a/pdf/pdf_colorspace.c +++ b/pdf/pdf_colorspace.c @@ -61,7 +61,7 @@ rgb_to_lab(fz_context *ctx, fz_colorspace *cs, float *rgb, float *lab) lab[2] = rgb[2]; } -static fz_colorspace k_device_lab = { -1, "Lab", 3, lab_to_rgb, rgb_to_lab }; +static fz_colorspace k_device_lab = { {-1, fz_free_colorspace_imp}, 0, "Lab", 3, lab_to_rgb, rgb_to_lab }; static fz_colorspace *fz_device_lab = &k_device_lab; /* Separation and DeviceN */ @@ -126,6 +126,7 @@ load_separation(pdf_xref *xref, fz_obj *array) cs->to_rgb = separation_to_rgb; cs->free_data = free_separation; cs->data = sep; + cs->size += sizeof(struct separation) + (base ? base->size : 0) + pdf_function_size(tint); return cs; } @@ -228,6 +229,7 @@ load_indexed(pdf_xref *xref, fz_obj *array) cs->to_rgb = indexed_to_rgb; cs->free_data = free_indexed; cs->data = idx; + cs->size += sizeof(*idx) + n + (base ? base->size : 0); if (fz_is_string(lookup) && fz_to_str_len(lookup) == n) { @@ -361,15 +363,15 @@ pdf_load_colorspace(pdf_xref *xref, fz_obj *obj) fz_context *ctx = xref->ctx; fz_colorspace *cs; - if ((cs = pdf_find_item(ctx, xref->store, (pdf_store_drop_fn *)fz_drop_colorspace, obj))) + if ((cs = fz_find_item(ctx, fz_free_colorspace_imp, obj))) { - return fz_keep_colorspace(cs); + return cs; } cs = pdf_load_colorspace_imp(xref, obj); /* RJW: "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj) */ - pdf_store_item(ctx, xref->store, (pdf_store_keep_fn *)fz_keep_colorspace, (pdf_store_drop_fn *)fz_drop_colorspace, obj, cs); + fz_store_item(ctx, obj, cs, cs->size); return cs; } diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c index dfd4782c..ae24df0f 100644 --- a/pdf/pdf_font.c +++ b/pdf/pdf_font.c @@ -198,6 +198,7 @@ pdf_load_substitute_font(fz_context *ctx, pdf_font_desc *fontdesc, int mono, int fz_throw(ctx, "cannot find substitute font"); fontdesc->font = fz_new_font_from_memory(ctx, data, len, 0); + fontdesc->size += len; /* RJW: "cannot load freetype font from memory" */ fontdesc->font->ft_substitute = 1; @@ -216,6 +217,7 @@ pdf_load_substitute_cjk_font(fz_context *ctx, pdf_font_desc *fontdesc, int ros, fz_throw(ctx, "cannot find builtin CJK font"); fontdesc->font = fz_new_font_from_memory(ctx, data, len, 0); + fontdesc->size += len; /* RJW: "cannot load builtin CJK font" */ fontdesc->font->ft_substitute = 1; @@ -288,6 +290,7 @@ pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *stmref) fz_drop_buffer(ctx, buf); fz_throw(ctx, "cannot load embedded font (%d %d R)", fz_to_num(stmref), fz_to_gen(stmref)); } + fontdesc->size += buf->len; /* save the buffer so we can free it later */ fontdesc->font->ft_data = buf->data; @@ -304,29 +307,31 @@ pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *stmref) pdf_font_desc * pdf_keep_font(pdf_font_desc *fontdesc) { - fontdesc->refs ++; - return fontdesc; + return (pdf_font_desc *)fz_keep_storable(&fontdesc->storable); } void pdf_drop_font(fz_context *ctx, pdf_font_desc *fontdesc) { - if (fontdesc && --fontdesc->refs == 0) - { - if (fontdesc->font) - fz_drop_font(ctx, fontdesc->font); - if (fontdesc->encoding) - pdf_drop_cmap(ctx, fontdesc->encoding); - if (fontdesc->to_ttf_cmap) - pdf_drop_cmap(ctx, fontdesc->to_ttf_cmap); - if (fontdesc->to_unicode) - pdf_drop_cmap(ctx, fontdesc->to_unicode); - fz_free(ctx, fontdesc->cid_to_gid); - fz_free(ctx, fontdesc->cid_to_ucs); - fz_free(ctx, fontdesc->hmtx); - fz_free(ctx, fontdesc->vmtx); - fz_free(ctx, fontdesc); - } + fz_drop_storable(ctx, &fontdesc->storable); +} + +static void +pdf_free_font_imp(fz_context *ctx, pdf_font_desc *fontdesc) +{ + if (fontdesc->font) + fz_drop_font(ctx, fontdesc->font); + if (fontdesc->encoding) + pdf_drop_cmap(ctx, fontdesc->encoding); + if (fontdesc->to_ttf_cmap) + pdf_drop_cmap(ctx, fontdesc->to_ttf_cmap); + if (fontdesc->to_unicode) + pdf_drop_cmap(ctx, fontdesc->to_unicode); + fz_free(ctx, fontdesc->cid_to_gid); + fz_free(ctx, fontdesc->cid_to_ucs); + fz_free(ctx, fontdesc->hmtx); + fz_free(ctx, fontdesc->vmtx); + fz_free(ctx, fontdesc); } pdf_font_desc * @@ -335,7 +340,8 @@ pdf_new_font_desc(fz_context *ctx) pdf_font_desc *fontdesc; fontdesc = fz_malloc(ctx, sizeof(pdf_font_desc)); - fontdesc->refs = 1; + FZ_INIT_STORABLE(fontdesc, 1, pdf_free_font_imp); + fontdesc->size = sizeof(pdf_font_desc); fontdesc->font = NULL; @@ -497,6 +503,7 @@ pdf_load_simple_font(pdf_xref *xref, fz_obj *dict) fz_warn(ctx, "freetype could not find any cmaps"); etable = fz_malloc_array(ctx, 256, sizeof(unsigned short)); + fontdesc->size += 256 * sizeof(unsigned short); for (i = 0; i < 256; i++) { estrings[i] = NULL; @@ -637,6 +644,7 @@ pdf_load_simple_font(pdf_xref *xref, fz_obj *dict) } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); + fontdesc->size += pdf_cmap_size(fontdesc->encoding); fontdesc->cid_to_gid_len = 256; fontdesc->cid_to_gid = etable; @@ -771,6 +779,7 @@ load_cid_font(pdf_xref *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_unicode { fz_throw(ctx, "syntaxerror: font missing encoding"); } + fontdesc->size += pdf_cmap_size(fontdesc->encoding); pdf_set_font_wmode(fontdesc, pdf_get_wmode(fontdesc->encoding)); @@ -787,6 +796,7 @@ load_cid_font(pdf_xref *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_unicode fontdesc->cid_to_gid_len = (buf->len) / 2; fontdesc->cid_to_gid = fz_malloc_array(ctx, fontdesc->cid_to_gid_len, sizeof(unsigned short)); + fontdesc->size += fontdesc->cid_to_gid_len * sizeof(unsigned short); for (i = 0; i < fontdesc->cid_to_gid_len; i++) fontdesc->cid_to_gid[i] = (buf->data[i * 2] << 8) + buf->data[i * 2 + 1]; @@ -1040,6 +1050,7 @@ pdf_make_width_table(fz_context *ctx, pdf_font_desc *fontdesc) font->width_count ++; font->width_table = fz_malloc_array(ctx, font->width_count, sizeof(int)); + fontdesc->size += font->width_count * sizeof(int); for (i = 0; i < fontdesc->hmtx_len; i++) { @@ -1062,9 +1073,8 @@ pdf_load_font(pdf_xref *xref, fz_obj *rdb, fz_obj *dict) fz_context *ctx = xref->ctx; pdf_font_desc *fontdesc; - if ((fontdesc = pdf_find_item(ctx, xref->store, (pdf_store_drop_fn *)pdf_drop_font, dict))) + if ((fontdesc = fz_find_item(ctx, pdf_free_font_imp, dict))) { - pdf_keep_font(fontdesc); return fontdesc; } @@ -1103,7 +1113,7 @@ pdf_load_font(pdf_xref *xref, fz_obj *rdb, fz_obj *dict) if (fontdesc->font->ft_substitute && !fontdesc->to_ttf_cmap) pdf_make_width_table(ctx, fontdesc); - pdf_store_item(ctx, xref->store, (pdf_store_keep_fn *)pdf_keep_font, (pdf_store_drop_fn *)pdf_drop_font, dict, fontdesc); + fz_store_item(ctx, dict, fontdesc, fontdesc->size); return fontdesc; } diff --git a/pdf/pdf_function.c b/pdf/pdf_function.c index fcd683ae..26d4bcec 100644 --- a/pdf/pdf_function.c +++ b/pdf/pdf_function.c @@ -19,7 +19,8 @@ enum struct pdf_function_s { - int refs; + fz_storable storable; + unsigned int size; int type; /* 0=sample 2=exponential 3=stitching 4=postscript */ int m; /* number of input values */ int n; /* number of output values */ @@ -849,6 +850,8 @@ load_postscript_func(pdf_function *func, pdf_xref *xref, fz_obj *dict, int num, fz_throw(ctx, "cannot parse calculator function (%d %d R)", num, gen); } + func->size += func->u.p.cap * sizeof(psobj); + fz_close(stream); } @@ -947,6 +950,7 @@ load_sample_func(pdf_function *func, pdf_xref *xref, fz_obj *dict, int num, int samplecount *= func->u.sa.size[i]; func->u.sa.samples = fz_malloc_array(ctx, samplecount, sizeof(float)); + func->size += samplecount * sizeof(float); stream = pdf_open_stream(xref, num, gen); /* RJW: "cannot open samples stream (%d %d R)", num, gen */ @@ -1198,6 +1202,7 @@ load_stitching_func(pdf_function *func, pdf_xref *xref, fz_obj *dict) /* RJW: "cannot load sub function %d (%d %d R)", i, fz_to_num(sub), fz_to_gen(sub) */ if (funcs[i]->m != 1 || funcs[i]->n != funcs[0]->n) fz_throw(ctx, "sub function %d /Domain or /Range mismatch", i); + func->size += pdf_function_size(funcs[i]); func->u.st.k ++; } @@ -1292,36 +1297,46 @@ eval_stitching_func(fz_context *ctx, pdf_function *func, float in, float *out) pdf_function * pdf_keep_function(pdf_function *func) { - func->refs ++; - return func; + return (pdf_function *)fz_keep_storable(&func->storable); } void pdf_drop_function(fz_context *ctx, pdf_function *func) { + fz_drop_storable(ctx, &func->storable); +} + +static void +pdf_free_function_imp(fz_context *ctx, void *func_) +{ + pdf_function *func = (pdf_function *)func_; int i; - if (--func->refs == 0) + + switch(func->type) { - switch(func->type) - { - case SAMPLE: - fz_free(ctx, func->u.sa.samples); - break; - case EXPONENTIAL: - break; - case STITCHING: - for (i = 0; i < func->u.st.k; i++) - pdf_drop_function(ctx, func->u.st.funcs[i]); - fz_free(ctx, func->u.st.funcs); - fz_free(ctx, func->u.st.bounds); - fz_free(ctx, func->u.st.encode); - break; - case POSTSCRIPT: - fz_free(ctx, func->u.p.code); - break; - } - fz_free(ctx, func); + case SAMPLE: + fz_free(ctx, func->u.sa.samples); + break; + case EXPONENTIAL: + break; + case STITCHING: + for (i = 0; i < func->u.st.k; i++) + pdf_drop_function(ctx, func->u.st.funcs[i]); + fz_free(ctx, func->u.st.funcs); + fz_free(ctx, func->u.st.bounds); + fz_free(ctx, func->u.st.encode); + break; + case POSTSCRIPT: + fz_free(ctx, func->u.p.code); + break; } + fz_free(ctx, func); +} + +unsigned int +pdf_function_size(pdf_function *func) +{ + return (func ? func->size : 0); } pdf_function * @@ -1332,15 +1347,15 @@ pdf_load_function(pdf_xref *xref, fz_obj *dict) fz_obj *obj; int i; - if ((func = pdf_find_item(ctx, xref->store, (pdf_store_drop_fn *)pdf_drop_function, dict))) + if ((func = fz_find_item(ctx, pdf_free_function_imp, dict))) { - pdf_keep_function(func); return func; } func = fz_malloc(ctx, sizeof(pdf_function)); memset(func, 0, sizeof *func); - func->refs = 1; + FZ_INIT_STORABLE(func, 1, pdf_free_function_imp); + func->size = sizeof(*func); obj = fz_dict_gets(dict, "FunctionType"); func->type = fz_to_int(obj); @@ -1414,7 +1429,7 @@ pdf_load_function(pdf_xref *xref, fz_obj *dict) "unknown")))), fz_to_num(dict), fz_to_gen(dict)); } - pdf_store_item(ctx, xref->store, (pdf_store_keep_fn *)pdf_keep_function, (pdf_store_drop_fn *)pdf_drop_function, dict, func); + fz_store_item(ctx, dict, func, func->size); return func; } diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c index 3af9c5f8..4266ded3 100644 --- a/pdf/pdf_image.c +++ b/pdf/pdf_image.c @@ -364,15 +364,15 @@ pdf_load_image(pdf_xref *xref, fz_obj *dict) fz_context *ctx = xref->ctx; fz_pixmap *pix; - if ((pix = pdf_find_item(ctx, xref->store, (pdf_store_drop_fn *)fz_drop_pixmap, dict))) + if ((pix = fz_find_item(ctx, fz_free_pixmap_imp, dict))) { - return fz_keep_pixmap(pix); + return pix; } pix = pdf_load_image_imp(xref, NULL, dict, NULL, 0); /* RJW: "cannot load image (%d 0 R)", fz_to_num(dict) */ - pdf_store_item(ctx, xref->store, (pdf_store_keep_fn *)fz_keep_pixmap, (pdf_store_drop_fn *)fz_drop_pixmap, dict, pix); + fz_store_item(ctx, dict, pix, fz_pixmap_size(pix)); return pix; } diff --git a/pdf/pdf_metrics.c b/pdf/pdf_metrics.c index 3aa0ef24..ae6383eb 100644 --- a/pdf/pdf_metrics.c +++ b/pdf/pdf_metrics.c @@ -72,6 +72,7 @@ pdf_end_hmtx(pdf_font_desc *font) if (!font->hmtx) return; qsort(font->hmtx, font->hmtx_len, sizeof(pdf_hmtx), cmph); + font->size += font->hmtx_cap * sizeof(pdf_hmtx); } void @@ -80,6 +81,7 @@ pdf_end_vmtx(pdf_font_desc *font) if (!font->vmtx) return; qsort(font->vmtx, font->vmtx_len, sizeof(pdf_vmtx), cmpv); + font->size += font->vmtx_cap * sizeof(pdf_vmtx); } pdf_hmtx diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c index fdc48ff3..d798eb2e 100644 --- a/pdf/pdf_page.c +++ b/pdf/pdf_page.c @@ -275,10 +275,6 @@ pdf_load_page(pdf_xref *xref, int number) if (number < 0 || number >= xref->page_len) fz_throw(ctx, "cannot find page %d", number + 1); - /* Ensure that we have a store for resource objects */ - if (!xref->store) - xref->store = pdf_new_store(ctx); - pageobj = xref->page_objs[number]; pageref = xref->page_refs[number]; diff --git a/pdf/pdf_pattern.c b/pdf/pdf_pattern.c index 194d9650..da890079 100644 --- a/pdf/pdf_pattern.c +++ b/pdf/pdf_pattern.c @@ -2,24 +2,54 @@ #include "mupdf.h" pdf_pattern * +pdf_keep_pattern(pdf_pattern *pat) +{ + return (pdf_pattern *)fz_keep_storable(&pat->storable); +} + +void +pdf_drop_pattern(fz_context *ctx, pdf_pattern *pat) +{ + fz_drop_storable(ctx, &pat->storable); +} + +static void +pdf_free_pattern_imp(fz_context *ctx, pdf_pattern *pat) +{ + if (pat->resources) + fz_drop_obj(pat->resources); + if (pat->contents) + fz_drop_buffer(ctx, pat->contents); + fz_free(ctx, pat); +} + +static unsigned int +pdf_pattern_size(pdf_pattern *pat) +{ + if (pat == NULL) + return 0; + return sizeof(*pat) + (pat->contents ? pat->contents->cap : 0); +} + +pdf_pattern * pdf_load_pattern(pdf_xref *xref, fz_obj *dict) { pdf_pattern *pat; fz_obj *obj; fz_context *ctx = xref->ctx; - if ((pat = pdf_find_item(ctx, xref->store, (pdf_store_drop_fn *)pdf_drop_pattern, dict))) + if ((pat = fz_find_item(ctx, pdf_free_pattern_imp, dict))) { - return pdf_keep_pattern(pat); + return pat; } pat = fz_malloc(ctx, sizeof(pdf_pattern)); - pat->refs = 1; + FZ_INIT_STORABLE(pat, 1, pdf_free_pattern_imp); pat->resources = NULL; pat->contents = NULL; /* Store pattern now, to avoid possible recursion if objects refer back to this one */ - pdf_store_item(ctx, xref->store, (pdf_store_keep_fn *)pdf_keep_pattern, (pdf_store_drop_fn *)pdf_drop_pattern, dict, pat); + fz_store_item(ctx, dict, pat, pdf_pattern_size(pat)); pat->ismask = fz_to_int(fz_dict_gets(dict, "PaintType")) == 2; pat->xstep = fz_to_real(fz_dict_gets(dict, "XStep")); @@ -44,29 +74,9 @@ pdf_load_pattern(pdf_xref *xref, fz_obj *dict) } fz_catch(ctx) { - pdf_remove_item(ctx, xref->store, (pdf_store_drop_fn *)pdf_drop_pattern, dict); + fz_remove_item(ctx, pdf_free_pattern_imp, dict); pdf_drop_pattern(ctx, pat); fz_throw(ctx, "cannot load pattern stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); } return pat; } - -pdf_pattern * -pdf_keep_pattern(pdf_pattern *pat) -{ - pat->refs ++; - return pat; -} - -void -pdf_drop_pattern(fz_context *ctx, pdf_pattern *pat) -{ - if (pat && --pat->refs == 0) - { - if (pat->resources) - fz_drop_obj(pat->resources); - if (pat->contents) - fz_drop_buffer(ctx, pat->contents); - fz_free(ctx, pat); - } -} diff --git a/pdf/pdf_shade.c b/pdf/pdf_shade.c index e0a2804b..52e2f199 100644 --- a/pdf/pdf_shade.c +++ b/pdf/pdf_shade.c @@ -976,7 +976,7 @@ pdf_load_shading_dict(pdf_xref *xref, fz_obj *dict, fz_matrix transform) fz_try(ctx) { shade = fz_malloc(ctx, sizeof(fz_shade)); - shade->refs = 1; + FZ_INIT_STORABLE(shade, 1, fz_free_shade_imp); shade->type = FZ_MESH; shade->use_background = 0; shade->use_function = 0; @@ -1077,6 +1077,14 @@ pdf_load_shading_dict(pdf_xref *xref, fz_obj *dict, fz_matrix transform) return shade; } +static unsigned int +fz_shade_size(fz_shade *s) +{ + if (s == NULL) + return 0; + return sizeof(*s) + s->mesh_cap * sizeof(*s->mesh) + s->colorspace->size; +} + fz_shade * pdf_load_shading(pdf_xref *xref, fz_obj *dict) { @@ -1085,9 +1093,9 @@ pdf_load_shading(pdf_xref *xref, fz_obj *dict) fz_context *ctx = xref->ctx; fz_shade *shade; - if ((shade = pdf_find_item(ctx, xref->store, (pdf_store_drop_fn *)fz_drop_shade, dict))) + if ((shade = fz_find_item(ctx, fz_free_shade_imp, dict))) { - return fz_keep_shade(shade); + return shade; } /* Type 2 pattern dictionary */ @@ -1123,7 +1131,7 @@ pdf_load_shading(pdf_xref *xref, fz_obj *dict) /* RJW: "cannot load shading dictionary (%d %d R)", fz_to_num(dict), fz_to_gen(dict) */ } - pdf_store_item(ctx, xref->store, (pdf_store_keep_fn *)fz_keep_shade, (pdf_store_drop_fn *)fz_drop_shade, dict, shade); + fz_store_item(ctx, dict, shade, fz_shade_size(shade)); return shade; } diff --git a/pdf/pdf_store.c b/pdf/pdf_store.c deleted file mode 100644 index 26a2ad9b..00000000 --- a/pdf/pdf_store.c +++ /dev/null @@ -1,224 +0,0 @@ -#include "fitz.h" -#include "mupdf.h" - -typedef struct pdf_item_s pdf_item; - -struct pdf_item_s -{ - pdf_store_drop_fn *drop_func; - fz_obj *key; - void *val; - int age; - pdf_item *next; -}; - -struct refkey -{ - pdf_store_drop_fn *drop_func; - int num; - int gen; -}; - -struct pdf_store_s -{ - fz_hash_table *hash; /* hash for num/gen keys */ - pdf_item *root; /* linked list for everything else */ -}; - -pdf_store * -pdf_new_store(fz_context *ctx) -{ - pdf_store *store; - store = fz_malloc(ctx, sizeof(pdf_store)); - store->hash = fz_new_hash_table(ctx, 4096, sizeof(struct refkey)); - store->root = NULL; - return store; -} - -void -pdf_store_item(fz_context *ctx, pdf_store *store, pdf_store_keep_fn *keep_func, pdf_store_drop_fn *drop_func, fz_obj *key, void *val) -{ - pdf_item *item; - - if (!store) - return; - - item = fz_malloc(ctx, sizeof(pdf_item)); - item->drop_func = drop_func; - item->key = fz_keep_obj(key); - item->val = keep_func(val); - item->age = 0; - item->next = NULL; - - if (fz_is_indirect(key)) - { - struct refkey refkey; - refkey.drop_func = drop_func; - refkey.num = fz_to_num(key); - refkey.gen = fz_to_gen(key); - fz_hash_insert(store->hash, &refkey, item); - } - else - { - item->next = store->root; - store->root = item; - } -} - -void * -pdf_find_item(fz_context *ctx, pdf_store *store, pdf_store_drop_fn *drop_func, fz_obj *key) -{ - struct refkey refkey; - pdf_item *item; - - if (!store) - return NULL; - - if (!key) - return NULL; - - if (fz_is_indirect(key)) - { - refkey.drop_func = drop_func; - refkey.num = fz_to_num(key); - refkey.gen = fz_to_gen(key); - item = fz_hash_find(store->hash, &refkey); - if (item) - { - item->age = 0; - return item->val; - } - } - else - { - for (item = store->root; item; item = item->next) - { - if (item->drop_func == drop_func && !fz_objcmp(item->key, key)) - { - item->age = 0; - return item->val; - } - } - } - - return NULL; -} - -void -pdf_remove_item(fz_context *ctx, pdf_store *store, pdf_store_drop_fn *drop_func, fz_obj *key) -{ - struct refkey refkey; - pdf_item *item, *prev, *next; - - if (fz_is_indirect(key)) - { - refkey.drop_func = drop_func; - refkey.num = fz_to_num(key); - refkey.gen = fz_to_gen(key); - item = fz_hash_find(store->hash, &refkey); - if (item) - { - fz_hash_remove(store->hash, &refkey); - item->drop_func(ctx, item->val); - fz_drop_obj(item->key); - fz_free(ctx, item); - } - } - else - { - prev = NULL; - for (item = store->root; item; item = next) - { - next = item->next; - if (item->drop_func == drop_func && !fz_objcmp(item->key, key)) - { - if (!prev) - store->root = next; - else - prev->next = next; - item->drop_func(ctx, item->val); - fz_drop_obj(item->key); - fz_free(ctx, item); - } - else - prev = item; - } - } -} - -void -pdf_age_store(fz_context *ctx, pdf_store *store, int maxage) -{ - struct refkey *refkey; - pdf_item *item, *prev, *next; - int i, n; - - n = fz_hash_len(store->hash); - for (i = 0; i < n; i++) - { - refkey = fz_hash_get_key(store->hash, i); - item = fz_hash_get_val(store->hash, i); - if (item && ++item->age > maxage) - { - fz_hash_remove(store->hash, refkey); - item->drop_func(ctx, item->val); - fz_drop_obj(item->key); - fz_free(ctx, item); - i--; /* items with same hash may move into place */ - } - } - - prev = NULL; - for (item = store->root; item; item = next) - { - next = item->next; - if (++item->age > maxage) - { - if (!prev) - store->root = next; - else - prev->next = next; - item->drop_func(ctx, item->val); - fz_drop_obj(item->key); - fz_free(ctx, item); - } - else - prev = item; - } -} - -void -pdf_free_store(fz_context *ctx, pdf_store *store) -{ - pdf_age_store(ctx, store, 0); - fz_free_hash(store->hash); - fz_free(ctx, store); -} - -void -pdf_debug_store(fz_context *ctx, pdf_store *store) -{ - pdf_item *item; - pdf_item *next; - struct refkey *refkey; - int i, n; - - printf("-- resource store contents --\n"); - - n = fz_hash_len(store->hash); - for (i = 0; i < n; i++) - { - refkey = fz_hash_get_key(store->hash, i); - item = fz_hash_get_val(store->hash, i); - if (item) - printf("store[%d] (%d %d R) = %p\n", i, refkey->num, refkey->gen, item->val); - } - - for (item = store->root; item; item = next) - { - next = item->next; - printf("store[*] "); - fz_debug_obj(item->key); - printf(" = %p\n", item->val); - } -} diff --git a/pdf/pdf_type3.c b/pdf/pdf_type3.c index c129350a..c63a2642 100644 --- a/pdf/pdf_type3.c +++ b/pdf/pdf_type3.c @@ -40,6 +40,7 @@ pdf_load_type3_font(pdf_xref *xref, fz_obj *rdb, fz_obj *dict) bbox = pdf_to_rect(ctx, obj); fontdesc->font = fz_new_type3_font(ctx, buf, matrix); + fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float)); fz_set_font_bbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); @@ -84,6 +85,7 @@ pdf_load_type3_font(pdf_xref *xref, fz_obj *rdb, fz_obj *dict) } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); + fontdesc->size += pdf_cmap_size(fontdesc->encoding); pdf_load_to_unicode(fontdesc, xref, estrings, NULL, fz_dict_gets(dict, "ToUnicode")); @@ -139,6 +141,7 @@ pdf_load_type3_font(pdf_xref *xref, fz_obj *rdb, fz_obj *dict) if (pdf_is_stream(xref, fz_to_num(obj), fz_to_gen(obj))) { fontdesc->font->t3procs[i] = pdf_load_stream(xref, fz_to_num(obj), fz_to_gen(obj)); + fontdesc->size += fontdesc->font->t3procs[i]->cap; } } } diff --git a/pdf/pdf_unicode.c b/pdf/pdf_unicode.c index 7968036a..95e7fa00 100644 --- a/pdf/pdf_unicode.c +++ b/pdf/pdf_unicode.c @@ -37,6 +37,7 @@ pdf_load_to_unicode(pdf_font_desc *font, pdf_xref *xref, pdf_sort_cmap(ctx, font->to_unicode); pdf_drop_cmap(ctx, cmap); + font->size += pdf_cmap_size(font->to_unicode); } else if (collection) @@ -60,6 +61,7 @@ pdf_load_to_unicode(pdf_font_desc *font, pdf_xref *xref, font->cid_to_ucs_len = 256; font->cid_to_ucs = fz_malloc_array(ctx, 256, sizeof(unsigned short)); + font->size += 256 * sizeof(unsigned short); for (i = 0; i < 256; i++) { diff --git a/pdf/pdf_xobject.c b/pdf/pdf_xobject.c index b4c03b8b..913ded37 100644 --- a/pdf/pdf_xobject.c +++ b/pdf/pdf_xobject.c @@ -2,25 +2,57 @@ #include "mupdf.h" pdf_xobject * +pdf_keep_xobject(pdf_xobject *xobj) +{ + return (pdf_xobject *)fz_keep_storable(&xobj->storable); +} + +void +pdf_drop_xobject(fz_context *ctx, pdf_xobject *xobj) +{ + fz_drop_storable(ctx, &xobj->storable); +} + +static void +pdf_free_xobject_imp(fz_context *ctx, pdf_xobject *xobj) +{ + if (xobj->colorspace) + fz_drop_colorspace(ctx, xobj->colorspace); + if (xobj->resources) + fz_drop_obj(xobj->resources); + if (xobj->contents) + fz_drop_buffer(ctx, xobj->contents); + fz_free(ctx, xobj); +} + +static unsigned int +pdf_xobject_size(pdf_xobject *xobj) +{ + if (xobj == NULL) + return 0; + return sizeof(*xobj) + (xobj->colorspace ? xobj->colorspace->size : 0) + (xobj->contents ? xobj->contents->len : 0); +} + +pdf_xobject * pdf_load_xobject(pdf_xref *xref, fz_obj *dict) { pdf_xobject *form; fz_obj *obj; fz_context *ctx = xref->ctx; - if ((form = pdf_find_item(ctx, xref->store, (pdf_store_drop_fn *)pdf_drop_xobject, dict))) + if ((form = fz_find_item(ctx, pdf_free_xobject_imp, dict))) { - return pdf_keep_xobject(form); + return form; } form = fz_malloc(ctx, sizeof(pdf_xobject)); - form->refs = 1; + FZ_INIT_STORABLE(form, 1, pdf_free_xobject_imp); form->resources = NULL; form->contents = NULL; form->colorspace = NULL; /* Store item immediately, to avoid possible recursion if objects refer back to this one */ - pdf_store_item(ctx, xref->store, (pdf_store_keep_fn *)pdf_keep_xobject, (pdf_store_drop_fn *)pdf_drop_xobject, dict, form); + fz_store_item(ctx, dict, form, pdf_xobject_size(form)); obj = fz_dict_gets(dict, "BBox"); form->bbox = pdf_to_rect(ctx, obj); @@ -66,32 +98,10 @@ pdf_load_xobject(pdf_xref *xref, fz_obj *dict) } fz_catch(ctx) { - pdf_remove_item(ctx, xref->store, (pdf_store_drop_fn *)pdf_drop_xobject, dict); + fz_remove_item(ctx, pdf_free_xobject_imp, dict); pdf_drop_xobject(ctx, form); fz_throw(ctx, "cannot load xobject content stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); } return form; } - -pdf_xobject * -pdf_keep_xobject(pdf_xobject *xobj) -{ - xobj->refs ++; - return xobj; -} - -void -pdf_drop_xobject(fz_context *ctx, pdf_xobject *xobj) -{ - if (xobj && --xobj->refs == 0) - { - if (xobj->colorspace) - fz_drop_colorspace(ctx, xobj->colorspace); - if (xobj->resources) - fz_drop_obj(xobj->resources); - if (xobj->contents) - fz_drop_buffer(ctx, xobj->contents); - fz_free(ctx, xobj); - } -} diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c index f79c6f9a..6b05e969 100644 --- a/pdf/pdf_xref.c +++ b/pdf/pdf_xref.c @@ -783,9 +783,6 @@ pdf_free_xref(pdf_xref *xref) return; ctx = xref->ctx; - if (xref->store) - pdf_free_store(ctx, xref->store); - if (xref->table) { for (i = 0; i < xref->len; i++) diff --git a/scripts/cmapdump.c b/scripts/cmapdump.c index 286f2abe..c8ae8134 100644 --- a/scripts/cmapdump.c +++ b/scripts/cmapdump.c @@ -49,7 +49,7 @@ main(int argc, char **argv) return 1; } - ctx = fz_new_context(&fz_alloc_default); + ctx = fz_new_context(&fz_alloc_default, FZ_STORE_UNLIMITED); if (!ctx) { fprintf(stderr, "cannot initialise context\n"); @@ -122,7 +122,7 @@ main(int argc, char **argv) } fprintf(fo, "static pdf_cmap cmap_%s = {\n", name); - fprintf(fo, "\t-1, "); + fprintf(fo, "\t{-1, pdf_free_cmap_imp}, "); fprintf(fo, "\"%s\", ", cmap->cmap_name); fprintf(fo, "\"%s\", 0, ", cmap->usecmap_name); fprintf(fo, "%d, ", cmap->wmode); @@ -175,3 +175,20 @@ void fz_new_aa_context(fz_context *ctx) void fz_free_aa_context(fz_context *ctx) { } + +void *fz_keep_storable(fz_storable *s) +{ + return s; +} + +void fz_drop_storable(fz_context *ctx, fz_storable *s) +{ +} + +void fz_new_store_context(fz_context *ctx, unsigned int max) +{ +} + +void fz_free_store_context(fz_context *ctx) +{ +} diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj index 52977dca..663f0268 100644 --- a/win32/libmupdf.vcproj +++ b/win32/libmupdf.vcproj @@ -311,10 +311,6 @@ > </File> <File - RelativePath="..\pdf\pdf_store.c" - > - </File> - <File RelativePath="..\pdf\pdf_stream.c" > </File> @@ -487,6 +483,10 @@ > </File> <File + RelativePath="..\fitz\res_store.c" + > + </File> + <File RelativePath="..\fitz\res_text.c" > </File> diff --git a/xps/xps_gradient.c b/xps/xps_gradient.c index b13d14ef..e5acc8a0 100644 --- a/xps/xps_gradient.c +++ b/xps/xps_gradient.c @@ -213,7 +213,7 @@ xps_draw_one_radial_gradient(xps_document *doc, fz_matrix ctm, /* TODO: this (and the stuff in pdf_shade) should move to res_shade.c */ shade = fz_malloc(doc->ctx, sizeof(fz_shade)); - shade->refs = 1; + FZ_INIT_STORABLE(shade, 1, fz_free_shade_imp); shade->colorspace = fz_device_rgb; shade->bbox = fz_infinite_rect; shade->matrix = fz_identity; @@ -254,7 +254,7 @@ xps_draw_one_linear_gradient(xps_document *doc, fz_matrix ctm, /* TODO: this (and the stuff in pdf_shade) should move to res_shade.c */ shade = fz_malloc(doc->ctx, sizeof(fz_shade)); - shade->refs = 1; + FZ_INIT_STORABLE(shade, 1, fz_free_shade_imp); shade->colorspace = fz_device_rgb; shade->bbox = fz_infinite_rect; shade->matrix = fz_identity; |