[gs-cvs] rev 7109 - trunk/gs/src

leonardo at ghostscript.com leonardo at ghostscript.com
Mon Oct 16 08:08:21 PDT 2006


Author: leonardo
Date: 2006-10-16 08:08:20 -0700 (Mon, 16 Oct 2006)
New Revision: 7109

Modified:
   trunk/gs/src/gsfont.c
   trunk/gs/src/gxccache.c
   trunk/gs/src/gxccman.c
   trunk/gs/src/gxfcache.h
   trunk/gs/src/gxfont.h
   trunk/gs/src/zfont.c
Log:
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.


Modified: trunk/gs/src/gsfont.c
===================================================================
--- trunk/gs/src/gsfont.c	2006-10-16 12:50:05 UTC (rev 7108)
+++ trunk/gs/src/gsfont.c	2006-10-16 15:08:20 UTC (rev 7109)
@@ -161,6 +161,7 @@
 	    (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 @@
     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 @@
 	     */
 #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 @@
 
     /* 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. */

Modified: trunk/gs/src/gxccache.c
===================================================================
--- trunk/gs/src/gxccache.c	2006-10-16 12:50:05 UTC (rev 7108)
+++ trunk/gs/src/gxccache.c	2006-10-16 15:08:20 UTC (rev 7109)
@@ -125,6 +125,10 @@
 	    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;
 	}

Modified: trunk/gs/src/gxccman.c
===================================================================
--- trunk/gs/src/gxccman.c	2006-10-16 12:50:05 UTC (rev 7108)
+++ trunk/gs/src/gxccman.c	2006-10-16 15:08:20 UTC (rev 7109)
@@ -209,6 +209,64 @@
 
 /* ====== 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 @@
 	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 @@
     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 @@
     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 @@
 				   (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 @@
 		     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 @@
 }
 
 /* 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 @@
 		    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. */

Modified: trunk/gs/src/gxfcache.h
===================================================================
--- trunk/gs/src/gxfcache.h	2006-10-16 12:50:05 UTC (rev 7108)
+++ trunk/gs/src/gxfcache.h	2006-10-16 15:08:20 UTC (rev 7109)
@@ -320,9 +320,15 @@
 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 */

Modified: trunk/gs/src/gxfont.h
===================================================================
--- trunk/gs/src/gxfont.h	2006-10-16 12:50:05 UTC (rev 7108)
+++ trunk/gs/src/gxfont.h	2006-10-16 15:08:20 UTC (rev 7109)
@@ -388,6 +388,10 @@
 					/* 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). */\

Modified: trunk/gs/src/zfont.c
===================================================================
--- trunk/gs/src/zfont.c	2006-10-16 12:50:05 UTC (rev 7108)
+++ trunk/gs/src/zfont.c	2006-10-16 15:08:20 UTC (rev 7109)
@@ -505,6 +505,11 @@
 	     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 @@
 			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;
 		}



More information about the gs-cvs mailing list