summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Melichev <igor.melichev@artifex.com>2006-10-16 15:08:20 +0000
committerIgor Melichev <igor.melichev@artifex.com>2006-10-16 15:08:20 +0000
commit77038b3ec1ff2ab45c6b57d41d49e622c50c6ed5 (patch)
treea63aa2aa66be0a023b467fee648fbb877a4fe2d4
parentc17d5535e9ef1b06e1b15865c88624c1a126f67a (diff)
Fix : Repair the character cache logics with persistent cache entries.
DETAILS : Important character caching problems have occasionally detected while merging with the ghostpcl branch : 1. The ttfReader never released in PCL when a font has a valud XUID. 1.1. The new function gs_clean_fm_pair_attributes, is called when a font is being released by 'restore', but its cached characters continue to live in the cache. This function releases those font-matrix pair attributes, which may point to the font. When the font has True Type data, it releases ttfReader and ttfFont. 1.2. The function gs_purge_font_from_char_caches is now called from gs_font_finalize, which is called from 'restore' and from the garbager. It allows gs_clean_fm_pair_attributes to be called from 'restore'. Note that when it is called from the garbager, it works idle because the method 'free' is disabled while the garabarer runs for same allocator. 1.3. The new flag gs_font::is_cached prevents a redundant work of gs_purge_font_from_char_caches, when it is called from font_restore and from gx_font_finalize. Therefore the argument of gs_purge_font_from_char_caches is now non_const. 1.4. With the new code, cached characters for fonts with valid XUIDs persist across a document/job end. They may be reused when a next document/job renders same font-matrix . There is no way to purge cache between jobs besides destructing entire cache and allocating it anew. 1.5. The new function gs_purge_font_from_char_caches_completely is coded for those clients, which don't need the feature 1.4. 1.6. Clients (such a PCL interpreter) must immediately call gs_purge_font_from_char_caches or gs_purge_font_from_char_caches_completely, whenever they release a font immediately. 2. Cached characters were dropped from cache on 'restore' while a font has a valid XUID and can appear again afrer 'restore'. It happened because the old code called gs_purge_font_from_char_caches from font_restore due to its cache elements point to the font's XUID, which is being released. 2.1. Copy the XUID to a stable memory in gx_add_fm_pair. 2.2. Release it in gs_purge_fm_pair. 2.3. Disable the related code portion in font_restore. 2.4. The new function gx_attach_tt_interpreter is factored out from gx_add_fm_pair. Now it is also called from gx_lookup_fm_pair (with an intermediate function gx_provide_fm_pair_attributes) when a persistent pair is being associated with a new font having same XUID. EXPECTED DIFFERENCES : None. git-svn-id: http://svn.ghostscript.com/ghostscript/trunk@7109 a1074d23-0009-0410-80fe-cf8c14f379e6
-rw-r--r--gs/src/gsfont.c6
-rw-r--r--gs/src/gxccache.c4
-rw-r--r--gs/src/gxccman.c189
-rw-r--r--gs/src/gxfcache.h8
-rw-r--r--gs/src/gxfont.h4
-rw-r--r--gs/src/zfont.c14
6 files changed, 179 insertions, 46 deletions
diff --git a/gs/src/gsfont.c b/gs/src/gsfont.c
index 98fc3ab30..3e38189a3 100644
--- a/gs/src/gsfont.c
+++ b/gs/src/gsfont.c
@@ -161,6 +161,7 @@ gs_font_finalize(void *vptr)
(ulong) pfont, (ulong) pfont->base, (ulong) prev, (ulong) next);
/* Notify clients that the font is being freed. */
gs_notify_all(&pfont->notify_list, NULL);
+ gs_purge_font_from_char_caches(pfont);
if (pfont->dir == 0)
ppfirst = 0;
else if (pfont->base == pfont)
@@ -307,6 +308,7 @@ gs_font_alloc(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
pfont->WMode = 0;
pfont->PaintType = 0;
pfont->StrokeWidth = 0;
+ pfont->is_cached = false;
pfont->procs = *procs;
memset(&pfont->orig_FontMatrix, 0, sizeof(pfont->orig_FontMatrix));
#endif
@@ -552,7 +554,7 @@ gs_makefont(gs_font_dir * pdir, const gs_font * pfont,
*/
#if 0 /* We disabled this code portion due to Bug 688392.
The problem was dangling pointers, which appear in fm_pair instances
- after uid_free is applied to applied to a font's UID,
+ after uid_free is applied to a font's UID,
because they share same xvalues array. We're unable to guess
for which reason uid_free was applied to the font's UID here
5+ years ago (see gsfont.c revision 1.1).
@@ -722,7 +724,7 @@ gs_purge_font(gs_font * pfont)
/* Purge the font from the font/matrix pair cache, */
/* including all cached characters rendered with that font. */
- return gs_purge_font_from_char_caches(pdir, pfont);
+ return gs_purge_font_from_char_caches(pfont);
}
/* Locate a gs_font by gs_id. */
diff --git a/gs/src/gxccache.c b/gs/src/gxccache.c
index 0f1de75be..837b9265e 100644
--- a/gs/src/gxccache.c
+++ b/gs/src/gxccache.c
@@ -125,6 +125,10 @@ gx_lookup_fm_pair(gs_font * pfont, const gs_matrix *char_tm,
code = gx_touch_fm_pair(dir, pair);
if (code < 0)
return code;
+ code = gx_provide_fm_pair_attributes(dir, pfont, pair,
+ char_tm, log2_scale, design_grid);
+ if (code < 0)
+ return code;
*ppair = pair;
return 0;
}
diff --git a/gs/src/gxccman.c b/gs/src/gxccman.c
index 0c06f1e52..f789fe44c 100644
--- a/gs/src/gxccman.c
+++ b/gs/src/gxccman.c
@@ -209,6 +209,64 @@ fm_pair_insert_into_list(gs_font_dir * dir, cached_fm_pair *pair, uint *head)
/* ====== Font-level routines ====== */
+private int
+gx_attach_tt_interpreter(gs_font_dir * dir,
+ gs_font_type42 *font, cached_fm_pair *pair,
+ const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
+ bool design_grid)
+{
+ float cxx, cxy, cyx, cyy;
+ gs_matrix m;
+ int code;
+
+ gx_compute_char_matrix(char_tm, log2_scale, &cxx, &cxy, &cyx, &cyy);
+ pair->design_grid = design_grid;
+ m.xx = cxx;
+ m.xy = cxy;
+ m.yx = cyx;
+ m.yy = cyy;
+ m.tx = m.ty = 0;
+ pair->ttr = gx_ttfReader__create(dir->memory);
+ if (!pair->ttr)
+ return_error(gs_error_VMerror);
+ /* We could use a single the reader instance for all fonts ... */
+ pair->ttf = ttfFont__create(dir);
+ if (!pair->ttf)
+ return_error(gs_error_VMerror);
+ gx_ttfReader__set_font(pair->ttr, (gs_font_type42 *)font);
+ code = ttfFont__Open_aux(pair->ttf, dir->tti, pair->ttr,
+ (gs_font_type42 *)font, &m, log2_scale, design_grid);
+ gx_ttfReader__set_font(pair->ttr, NULL);
+ return code;
+}
+
+private inline
+does_font_need_tt_interpreter(gs_font *font)
+{
+ if (font->FontType == ft_TrueType || font->FontType == ft_CID_TrueType) {
+ gs_font_type42 *pfont = (gs_font_type42 *)font;
+
+ if (pfont->FAPI==NULL && pfont->data.USE_ttfReader)
+ return true;
+ }
+ return false;
+}
+
+int
+gx_provide_fm_pair_attributes(gs_font_dir * dir,
+ gs_font *font, cached_fm_pair *pair,
+ const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
+ bool design_grid)
+{
+ if (does_font_need_tt_interpreter(font)) {
+ if (pair->ttf != NULL)
+ return 0; /* Already attached. */
+ return gx_attach_tt_interpreter(dir, (gs_font_type42 *)font, pair,
+ char_tm, log2_scale, design_grid);
+ }
+ return 0;
+}
+
/* Add a font/matrix pair to the cache. */
/* (This is only exported for gxccache.c.) */
int
@@ -255,12 +313,21 @@ gx_add_fm_pair(register gs_font_dir * dir, gs_font * font, const gs_uid * puid,
pair = dir->fmcache.mdata + dir->fmcache.unused;
dir->fmcache.unused++;
}
+ font->is_cached = true; /* Set this early to ensure
+ gs_purge_font_from_char_caches works for it in case of errors. */
dir->fmcache.msize++;
code = fm_pair_insert_into_list(dir, pair, &dir->fmcache.used);
if (code < 0)
return code;
pair->font = font;
pair->UID = *puid;
+ /* Copy UID into a stable memory,
+ so that 'restore' may keep this pair. */
+ code = uid_copy(&pair->UID, dir->memory->stable_memory, "gx_add_fm_pair");
+ if (code < 0) {
+ uid_set_invalid(&pair->UID);
+ return code;
+ }
pair->FontType = font->FontType;
/* The OSF/1 compiler doesn't like casting a pointer to */
/* a shorter int.... */
@@ -273,29 +340,9 @@ gx_add_fm_pair(register gs_font_dir * dir, gs_font * font, const gs_uid * puid,
pair->ttf = 0;
pair->ttr = 0;
pair->design_grid = false;
- if (font->FontType == ft_TrueType || font->FontType == ft_CID_TrueType)
- if (((gs_font_type42 *)font)->FAPI==NULL && ((gs_font_type42 *)font)->data.USE_ttfReader ) {
- float cxx, cxy, cyx, cyy;
- gs_matrix m;
- gx_compute_char_matrix(char_tm, log2_scale, &cxx, &cxy, &cyx, &cyy);
-
- pair->design_grid = design_grid;
- m.xx = cxx;
- m.xy = cxy;
- m.yx = cyx;
- m.yy = cyy;
- m.tx = m.ty = 0;
- pair->ttr = gx_ttfReader__create(dir->memory);
- if (!pair->ttr)
- return_error(gs_error_VMerror);
- /* We could use a single the reader instance for all fonts ... */
- pair->ttf = ttfFont__create(dir);
- if (!pair->ttf)
- return_error(gs_error_VMerror);
- gx_ttfReader__set_font(pair->ttr, (gs_font_type42 *)font);
- code = ttfFont__Open_aux(pair->ttf, dir->tti, pair->ttr,
- (gs_font_type42 *)font, &m, log2_scale, design_grid);
- gx_ttfReader__set_font(pair->ttr, NULL);
+ if (does_font_need_tt_interpreter(font)) {
+ code = gx_attach_tt_interpreter(dir, (gs_font_type42 *)font, pair,
+ char_tm, log2_scale, design_grid);
if (code < 0)
return code;
}
@@ -403,6 +450,26 @@ purge_fm_pair_char_xfont(const gs_memory_t *mem, cached_char * cc, void *vpair)
return cc_pair(cc) == cpair && cpair->xfont == 0 && !cc_has_bits(cc);
}
#undef cpair
+
+private inline void
+gs_clean_fm_pair_attributes(gs_font_dir * dir, cached_fm_pair * pair)
+{
+ if (pair->ttr)
+ gx_ttfReader__destroy(pair->ttr);
+ pair->ttr = 0;
+ if (pair->ttf)
+ ttfFont__destroy(pair->ttf, dir);
+ pair->ttf = 0;
+}
+
+void
+gs_clean_fm_pair(gs_font_dir * dir, cached_fm_pair * pair)
+{
+ if_debug1('k', "[k]cleaning pair 0x%lx%s\n", (ulong) pair);
+ pair->font = NULL;
+ gs_clean_fm_pair_attributes(dir, pair);
+}
+
int
gs_purge_fm_pair(gs_font_dir * dir, cached_fm_pair * pair, int xfont_only)
{
@@ -418,12 +485,7 @@ gs_purge_fm_pair(gs_font_dir * dir, cached_fm_pair * pair, int xfont_only)
(xfont_only ? purge_fm_pair_char_xfont :
purge_fm_pair_char),
pair);
- if (pair->ttr)
- gx_ttfReader__destroy(pair->ttr);
- pair->ttr = 0;
- if (pair->ttf)
- ttfFont__destroy(pair->ttf, dir);
- pair->ttf = 0;
+ gs_clean_fm_pair_attributes(dir, pair);
if (!xfont_only) {
int code;
@@ -433,6 +495,11 @@ gs_purge_fm_pair(gs_font_dir * dir, cached_fm_pair * pair, int xfont_only)
pair->num_chars);
}
#endif
+ { /* Free xvalues here because gx_add_fm_pair copied
+ them into the stable memory dir->memory. */
+ gs_free_object(dir->memory->stable_memory, pair->UID.xvalues, "gs_purge_fm_pair");
+ pair->UID.xvalues = 0;
+ }
fm_pair_set_free(pair);
code = fm_pair_remove_from_list(dir, pair, &dir->fmcache.used);
if (code < 0)
@@ -811,18 +878,27 @@ gx_add_char_bits(gs_font_dir * dir, cached_char * cc,
}
/* Purge from the caches all references to a given font. */
-int
-gs_purge_font_from_char_caches(gs_font_dir * dir, const gs_font * font)
+private int
+gs_purge_font_from_char_caches_forced(gs_font * font, bool force)
{
- cached_fm_pair *pair = dir->fmcache.mdata;
- int count = dir->fmcache.mmax;
+ gs_font_dir * dir;
+ cached_fm_pair *pair;
+ int count;
+ if (font->dir == NULL)
+ return 0; /* The font was not properly build due to errors. */
+ if (!font->is_cached)
+ return 0;
+ dir = font->dir;
+ pair = dir->fmcache.mdata;
+ count = dir->fmcache.mmax;
+ font->is_cached = false; /* Prevent redundant execution. */
if_debug1('k', "[k]purging font 0x%lx\n",
(ulong) font);
- while (count--) {
+ for (; count--; pair++) {
if (pair->font == font) {
- if (uid_is_valid(&pair->UID)) { /* Keep the entry. */
- pair->font = 0;
+ if (!force && uid_is_valid(&pair->UID)) { /* Keep the entry. */
+ gs_clean_fm_pair(dir, pair);
} else {
int code = gs_purge_fm_pair(dir, pair, 0);
@@ -830,11 +906,50 @@ gs_purge_font_from_char_caches(gs_font_dir * dir, const gs_font * font)
return code;
}
}
- pair++;
}
return 0;
}
+/* Purge from the caches all references to a given font,
+ with leaving persistent chars in the cache. */
+int
+gs_purge_font_from_char_caches(gs_font * font)
+{
+ /* This function is called when a font is being released.
+ The purpose is to remove all cache attributes,
+ which may point to the font data.
+ Note : when a font has a valid XUID,
+ it doesn't release cache entries and cached chars,
+ so that they may be used in future
+ if a font with same XUID appears again.
+ All this improves the performance when
+ a document executes a sequence like this :
+
+ n {
+ save /fontname findfont 10 scalefont
+ (xyz) show
+ restore
+ } repeat
+ */
+ return gs_purge_font_from_char_caches_forced(font, false);
+}
+
+/* Purge from the caches all references to a given font,
+ without leaving persistent chars in the cache. */
+int
+gs_purge_font_from_char_caches_completely(gs_font * font)
+{
+ /* A client should call this finction
+ when it frees a font,
+ and the client doesn't need to leave
+ persistent cache entries for this font
+ even if the font has a valid XUID.
+ */
+ return gs_purge_font_from_char_caches_forced(font, true);
+}
+
+
+
/* ------ Internal routines ------ */
/* Allocate data space for a cached character, adding a new chunk if needed. */
diff --git a/gs/src/gxfcache.h b/gs/src/gxfcache.h
index 32aa9af31..f5fd9ee87 100644
--- a/gs/src/gxfcache.h
+++ b/gs/src/gxfcache.h
@@ -320,9 +320,15 @@ int gx_lookup_fm_pair(gs_font * pfont, const gs_matrix *char_tm,
int gx_add_fm_pair(register gs_font_dir * dir, gs_font * font, const gs_uid * puid,
const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
bool design_grid, cached_fm_pair **ppair);
+int gx_fm_pair_attributes(gs_font_dir * dir,
+ gs_font *font, cached_fm_pair *pair,
+ const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
+ bool design_grid);
int gx_touch_fm_pair(gs_font_dir *dir, cached_fm_pair *pair);
void gx_lookup_xfont(const gs_state *, cached_fm_pair *, int);
+void gs_clean_fm_pair(gs_font_dir * dir, cached_fm_pair * pair);
int gs_purge_fm_pair(gs_font_dir *, cached_fm_pair *, int);
-int gs_purge_font_from_char_caches(gs_font_dir *, const gs_font *);
+int gs_purge_font_from_char_caches(gs_font *);
+int gs_purge_font_from_char_caches_completely(gs_font * font);
#endif /* gxfcache_INCLUDED */
diff --git a/gs/src/gxfont.h b/gs/src/gxfont.h
index 8934bb2d3..86c45422c 100644
--- a/gs/src/gxfont.h
+++ b/gs/src/gxfont.h
@@ -388,6 +388,10 @@ typedef struct gs_font_name_s {
/* 0 for others */\
float StrokeWidth; /* StrokeWidth for Type 1/4/42 */\
/* fonts (if present), 0 for others */\
+ bool is_cached; /* Prevents redundant executions of */\
+ /* gs_purge_font_from_char_caches, */\
+ /* when it is called from 'font_restore' */\
+ /* and from gx_font_finalize. */\
gs_font_procs procs;\
/* We store both the FontDirectory key (key_name) and, */\
/* if present, the FontName (font_name). */\
diff --git a/gs/src/zfont.c b/gs/src/zfont.c
index 757fd91f7..06b95aaf0 100644
--- a/gs/src/zfont.c
+++ b/gs/src/zfont.c
@@ -505,6 +505,11 @@ top:
n > 0; pair++, n--
)
if (!fm_pair_is_free(pair)) {
+#if 0
+ /* We disabled this code portion because
+ gx_add_fm_pair now copied xvalues
+ into a stable memory.
+ */
if ((uid_is_XUID(&pair->UID) &&
alloc_is_since_save((char *)pair->UID.xvalues,
save))
@@ -514,15 +519,12 @@ top:
return code;
continue;
}
+#endif
if (pair->font != 0 &&
alloc_is_since_save((char *)pair->font, save)
) {
- if (!uid_is_valid(&pair->UID)) {
- code = gs_purge_fm_pair(pdir, pair, 0);
- if (code < 0)
- return code;
- continue;
- }
+ if (!uid_is_valid(&pair->UID))
+ gs_clean_fm_pair(pdir, pair);
/* Don't discard pairs with a surviving UID. */
pair->font = 0;
}