summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/pdfapp.c6
-rw-r--r--apps/pdfclean.c2
-rw-r--r--apps/pdfdraw.c4
-rw-r--r--apps/pdfextract.c2
-rw-r--r--apps/pdfshow.c2
-rw-r--r--apps/win_main.c2
-rw-r--r--apps/xpsdraw.c2
-rw-r--r--fitz/base_context.c6
-rw-r--r--fitz/fitz.h51
-rw-r--r--fitz/res_colorspace.c35
-rw-r--r--fitz/res_pixmap.c58
-rw-r--r--fitz/res_shade.c22
-rw-r--r--fitz/res_store.c364
-rw-r--r--pdf/mupdf.h32
-rw-r--r--pdf/pdf_cmap.c31
-rw-r--r--pdf/pdf_cmap_load.c20
-rw-r--r--pdf/pdf_colorspace.c10
-rw-r--r--pdf/pdf_font.c54
-rw-r--r--pdf/pdf_function.c69
-rw-r--r--pdf/pdf_image.c6
-rw-r--r--pdf/pdf_metrics.c2
-rw-r--r--pdf/pdf_page.c4
-rw-r--r--pdf/pdf_pattern.c60
-rw-r--r--pdf/pdf_shade.c16
-rw-r--r--pdf/pdf_store.c224
-rw-r--r--pdf/pdf_type3.c3
-rw-r--r--pdf/pdf_unicode.c2
-rw-r--r--pdf/pdf_xobject.c64
-rw-r--r--pdf/pdf_xref.c3
-rw-r--r--scripts/cmapdump.c21
-rw-r--r--win32/libmupdf.vcproj8
-rw-r--r--xps/xps_gradient.c4
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;