summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'base/gsgcache.c')
-rw-r--r--base/gsgcache.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/base/gsgcache.c b/base/gsgcache.c
new file mode 100644
index 00000000..cc0fd50d
--- /dev/null
+++ b/base/gsgcache.c
@@ -0,0 +1,215 @@
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* Glyph data cache methods. */
+
+#include "gx.h"
+#include "gserrors.h"
+#include "memory_.h"
+#include "gsstruct.h"
+#include "gsgdata.h"
+#include "gsgcache.h"
+#include "gxfont.h"
+#include "gxfont42.h"
+
+/*
+ * This implementation hardcodes the type 42 font type.
+ * We could generalize it, but since CIDFontType 0 uses
+ * a PS procedure for reading glyphs, it is hardly applicable.
+ *
+ * The caching is mostly useful for glyphs with multiple components,
+ * but CIDFontType 0 has 2 components max, which are relatively seldom.
+ * Also it is low useful for fonts, which fully loaded into RAM.
+ * FAPI does not need a caching, because renderer pludins access
+ * font data through a file handle by own means.
+ *
+ * Due to all above, currently the caching is applied
+ * only while emulating CIDFontType 2 with a True Type file.
+ */
+
+typedef struct gs_glyph_cache_elem_s gs_glyph_cache_elem;
+struct gs_glyph_cache_elem_s {
+ gs_glyph_data_t gd;
+ uint glyph_index;
+ uint lock_count;
+ gs_glyph_cache_elem *next;
+};
+gs_private_st_composite(st_glyph_cache_elem, gs_glyph_cache_elem, "gs_glyph_cache_elem",
+ gs_glyph_cache_elem_enum_ptrs, gs_glyph_cache_elem_reloc_ptrs);
+
+static
+ENUM_PTRS_WITH(gs_glyph_cache_elem_enum_ptrs, gs_glyph_cache_elem *e)
+{
+ index --;
+ if (index < ST_GLYPH_DATA_NUM_PTRS)
+ return ENUM_USING(st_glyph_data, &e->gd, sizeof(e->gd), index);
+ return 0;
+}
+ENUM_PTR(0, gs_glyph_cache_elem, next);
+ENUM_PTRS_END
+static RELOC_PTRS_WITH(gs_glyph_cache_elem_reloc_ptrs, gs_glyph_cache_elem *e)
+{
+ RELOC_PTR(gs_glyph_cache_elem, next);
+ RELOC_USING(st_glyph_data, &e->gd, sizeof(e->gd));
+} RELOC_PTRS_END
+
+struct gs_glyph_cache_s {
+ int total_size;
+ gs_glyph_cache_elem *list;
+ gs_memory_t *memory;
+ gs_font_type42 *pfont;
+ stream *s;
+ get_glyph_data_from_file read_data;
+};
+gs_private_st_ptrs4(st_glyph_cache, gs_glyph_cache, "gs_glyph_cache",
+ gs_glyph_cache_enum_ptrs, gs_glyph_cache_reloc_ptrs, list, memory, pfont, s);
+
+GS_NOTIFY_PROC(gs_glpyh_cache__release);
+
+gs_glyph_cache *
+gs_glyph_cache__alloc(gs_font_type42 *pfont, stream *s,
+ get_glyph_data_from_file read_data)
+{
+ gs_memory_t *mem = pfont->memory->stable_memory;
+ gs_glyph_cache *gdcache = (gs_glyph_cache *)gs_alloc_struct(mem,
+ gs_glyph_cache, &st_glyph_cache, "gs_glyph_cache");
+ if (gdcache == 0)
+ return 0;
+ gdcache->total_size = 0;
+ gdcache->list = NULL;
+ gdcache->pfont = pfont;
+ gdcache->s = s;
+ /*
+ * The cache elements need to be in stable memory so they don't
+ * get removed by 'restore' (elements can be created at a different
+ * save level than the current level)
+ */
+ gdcache->memory = mem;
+ gdcache->read_data = read_data;
+ gs_font_notify_register((gs_font *)pfont, gs_glyph_cache__release, (void *)gdcache);
+ return gdcache;
+}
+
+int
+gs_glyph_cache__release(void *data, void *event)
+{
+ gs_glyph_cache *self = (gs_glyph_cache *)data;
+ gs_glyph_cache_elem *e = self->list;
+ gs_font_type42 *pfont = self->pfont;
+
+ while (e != NULL) {
+ gs_glyph_cache_elem *next_e;
+
+ next_e = e->next;
+ e->gd.procs->free(&e->gd, "gs_glyph_cache__release");
+ gs_free_object(self->memory, e, "gs_glyph_cache_elem__release");
+ e = next_e;
+ }
+ self->list = NULL;
+ gs_font_notify_unregister((gs_font *)pfont, gs_glyph_cache__release, (void *)self);
+ gs_free_object(self->memory, self, "gs_glyph_cache__release");
+ return 0;
+}
+
+static gs_glyph_cache_elem **
+gs_glyph_cache_elem__locate(gs_glyph_cache *self, uint glyph_index)
+{ /* If not fond, returns an unlocked element. */
+ gs_glyph_cache_elem **e = &self->list, **p_unlocked = NULL;
+ int count = 0; /* debug purpose only */
+
+ for (; *e != 0; e = &(*e)->next, count++) {
+ if ((*e)->glyph_index == glyph_index) {
+ return e;
+ }
+ if ((*e)->lock_count == 0)
+ p_unlocked = e;
+ }
+ return p_unlocked;
+}
+
+static inline void
+gs_glyph_cache_elem__move_to_head(gs_glyph_cache *self, gs_glyph_cache_elem **pe)
+{ gs_glyph_cache_elem *e = *pe;
+
+ *pe = e->next;
+ e->next = self->list;
+ self->list = e;
+}
+
+/* Manage the glyph data using the font's allocator. */
+static void
+gs_glyph_cache_elem__free_data(gs_glyph_data_t *pgd, client_name_t cname)
+{ gs_glyph_cache_elem *e = (gs_glyph_cache_elem *)pgd->proc_data;
+
+ e->lock_count--;
+}
+static int
+gs_glyph_cache_elem__substring(gs_glyph_data_t *pgd, uint offset, uint size)
+{ gs_glyph_cache_elem *e = (gs_glyph_cache_elem *)pgd->proc_data;
+
+ e->lock_count++;
+ return_error(gs_error_unregistered); /* Unsupported; should not happen. */
+}
+
+static const gs_glyph_data_procs_t gs_glyph_cache_elem_procs = {
+ gs_glyph_cache_elem__free_data, gs_glyph_cache_elem__substring
+};
+
+int
+gs_get_glyph_data_cached(gs_font_type42 *pfont, uint glyph_index, gs_glyph_data_t *pgd)
+{ gs_glyph_cache *gdcache = pfont->data.gdcache;
+ gs_glyph_cache_elem **pe = gs_glyph_cache_elem__locate(gdcache, glyph_index);
+ gs_glyph_cache_elem *e = NULL;
+
+ if (pe == NULL || (*pe)->glyph_index != glyph_index) {
+ int code;
+
+ if (pe != NULL && gdcache->total_size > 32767 /* arbitrary */ &&
+ (*pe)->lock_count <= 0) {
+ /* Release the element's data, and move it : */
+ e = *pe;
+ gdcache->total_size -= e->gd.bits.size + sizeof(*e);
+ e->gd.procs->free(&e->gd, "gs_get_glyph_data_cached");
+ gs_glyph_cache_elem__move_to_head(gdcache, pe);
+ } else {
+ /* Allocate new head element. */
+ e = (gs_glyph_cache_elem *)gs_alloc_struct(gdcache->memory,
+ gs_glyph_cache_elem, &st_glyph_cache_elem, "gs_glyph_cache_elem");
+ if (e == NULL)
+ return_error(gs_error_VMerror);
+ memset(e, 0, sizeof(*e));
+ e->next = gdcache->list;
+ gdcache->list = e;
+ e->gd.memory = gdcache->memory;
+ }
+ /* Load the element's data : */
+ code = (*gdcache->read_data)(pfont, gdcache->s, glyph_index, &e->gd);
+ if (code < 0)
+ return code;
+ gdcache->total_size += e->gd.bits.size + sizeof(*e);
+ e->glyph_index = glyph_index;
+ } else {
+ /* Move the element : */
+ e = *pe;
+ gs_glyph_cache_elem__move_to_head(gdcache, pe);
+ }
+ /* Copy data and set procs : */
+ pgd->bits = e->gd.bits;
+ pgd->proc_data = e;
+ pgd->procs = &gs_glyph_cache_elem_procs;
+ e->lock_count++;
+ return 0;
+}