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

ken at ghostscript.com ken at ghostscript.com
Tue Oct 2 00:31:59 PDT 2007


Author: ken
Date: 2007-10-02 00:31:58 -0700 (Tue, 02 Oct 2007)
New Revision: 8265

Modified:
   trunk/gs/src/gdevpdfd.c
   trunk/gs/src/gdevpdfg.c
   trunk/gs/src/gdevpdfg.h
   trunk/gs/src/gdevpdfx.h
   trunk/gs/src/gdevpdti.c
   trunk/gs/src/gdevpdts.c
   trunk/gs/src/gdevpdts.h
   trunk/gs/src/gdevpdtt.c
   trunk/gs/src/gdevpdtt.h
   trunk/gs/src/gxchar.c
   trunk/gs/src/gxpath.c
   trunk/gs/src/gzpath.h
Log:
pdfwrite: Convert 'text' followed by 'text charpath stroke' to a single text
operation by using text rendering mode 2.

DETAILS:
Bug #689310 "Offset between text and outline in pdfwrite.dev"

Emitting text, followed by the same text as an argument to charpath, and then stroking the
resulting path previously resulted in a large path being emitted and stroked in the PDF file. 

This is inefficient, but worse the path is not grid fitted, whereas the text is. When
used to stroke the outline of previously rendered text, either in a different colour or to
create a 'bold' effect, the emitted path did not always precisely match the rendered text.

This change is to emit this PostScript construct using the closest available match in PDF, 
which is the text rendering mode. There are two parts to this change, firstly to identify 
when a path is the result of a charpath, and secondly to merge text followed by charpath/stroke
operations into a single operation on output.

1. (gzpath.h) Add a new member 'last_charpath_segment' to the gx_path_s structure. Update the
   path garbage collection code for relocation of new variable.

2. (gxpath.c) Initialise the new member 'last_charpath_segment' to 0 in
   gx_path_init_contents, and also in path_alloc_copy to prevent copies being identified as
   the result of a charpath.

3. (gxchar.c) We need to be able to tell if a path was the result of a charpath. To do this
   we store the final segment of a path in 'last_charpath_segment' of the path
   structure during show_finish, if the current operation was a charpath. See also item 11.

4. (gdevpdfx.h) Add a new member 'last_charpath_op' to the gx_device_pdf_s structure, to
   hold the boolean argument associated with a charpath operation. Also add to the 
   pdf_substream_s structure to allow us to save and restore this value on entry to or
   exit from a PDF substream.

5. (gdevpdti.c) Save and restore the value of last_charpath_op in pdf_enter_substream
   and pdf_exit_substream.

6. (gdevpdfx.h) Add a new member variable 'last_charpath_op' to the 'pdf_substream_save_s' 
   structure to allow us to save and restore the last_charpath_op as noted above.

7. (gdevpdtt.c) During gdev_pdf_text_begin, if the operation is a charpath, check the
   following conditions, if met then store a copy of the charpath boolean variable in 
   a new member of the gx_device_pdf_s structure.
       1. Operation must be a charpath
       2. Current path must be empty (can't handle charpath concatenated to existing path)
       3. The font being used for the current text must be the same as the font used for
          the previous stored (but not yet emitted) text.
       4. The initial point of the text for the charpath must match the initial point of
          the previous stored text.
       5. The text bytes must be the same as the previous stored text.
       6. The point size of the text must match the previous stored text.
   Also, move the calculation of the font point size out of pdf_update_text_state so that
   we can calculate the size in pdf_compare_text_state_for_charpath' defined in 9 below
   without duplicating code.

8. (gdevpdtt.h) Prototype 'pdf_calculate_text_size'

9. (gdevpdts.c) Add a new function 'pdf_compare_text_state_for_charpath' to do the 
   checking noted above. The pdf_text_state_s structure is not defined publicly, so 
   we need code to access its members. Also add a function 'pdf_modify_text_render_mode'
   which will attempt to add a rendering mode (stroke, fill or clip) to existing text
   by updating the existing text rendering mode. Returns 0 if the existing text cannot
   be modified, and we fall back to emitting a path and stroke.

10. (gdevpdts.h) Add prototypes for the functions required in 9.

11. (gdevpdfd.c) In pdf_stroke_path, if the 'last_charpath_op' member of the pdf device
   structure is set, perform some more checks (below) and if passed, set the text render
   mode of the stored text, set the stroke colour, set the line width, and force the stored
   text to be emitted. This conveniently results in a gsave/grestore pair round the
   graphics state changes.
      1. The last charpath operation must have been 'false charpath'
      2. There must be a non-empty path (result of the charpath operation)
      3. The 'last_charpath_segment' stored in the path must match the actual last segment
         in the path. (can't handle path segments added to the result of a charpath)

12. (gdevpdfg.h) Make the pdf_reset_color routine public, as we need to be able to set the 
   colour from pdf_stroke_path.

13. (gddevpdfg.c) We need to be able to set a stroke colour while in a TEXT context,
   previously the routine pdf_reset_color, which emits colours and spaces, immediately
   switched to a STREAM context, which caused pending text to be flushed. pdf_reset_color
   was only called from two places, pdf_set_drawing_color and pdf_set_pure_color. The
   switch to a STREAM context has been moved to these routines, leaving pdf_reset_color to
   actually do the work without worrying about the context.
   It was found necessary to also reproduce some checks before switching context, to
   prevent unnecessary context switches.
   Removed unused local variable 'process_color' from pdf_reset_color.

There is scope for additional enhancement with this code. Presently there is no attempt to
deal with 'charpath gsave fill grestore stroke' constructs, nor to handle clipping paths 
resulting from charpath. There may be other possibilities.


EXPECTED DIFFERENCES:
A progression with pdfwrite and Bug687812.ps. The 'n' glyph is now rendered using text
render mode 2 instead of Tj followed by a complex path. Previously there were a few areas
where the text and the path differed by a pixel when the PDF file was rendered. This no
longer occurs.



Modified: trunk/gs/src/gdevpdfd.c
===================================================================
--- trunk/gs/src/gdevpdfd.c	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdfd.c	2007-10-02 07:31:58 UTC (rev 8265)
@@ -34,6 +34,8 @@
 #include "gdevpdfg.h"
 #include "gdevpdfo.h"
 #include "gsutil.h"
+#include "gdevpdtf.h"
+#include "gdevpdts.h"
 
 /* ---------------- Drawing ---------------- */
 
@@ -1213,8 +1215,37 @@
 	return 0;		/* won't mark the page */
     if (pdf_must_put_clip_path(pdev, pcpath))
 	code = pdf_unclip(pdev);
-    else 
-	code = pdf_open_page(pdev, PDF_IN_STREAM);
+    else if ((pdev->last_charpath_op & TEXT_DO_FALSE_CHARPATH) && ppath->current_subpath && 
+	(ppath->last_charpath_segment == ppath->current_subpath->last)) {
+	bool hl_color = pdf_can_handle_hl_color((gx_device_vector *)pdev, pis, pdcolor);
+	const gs_imager_state *pis_for_hl_color = (hl_color ? pis : NULL);
+	
+	if (pdf_modify_text_render_mode(pdev->text->text_state, 1)) {
+	    /* Set the colour for the stroke */
+	    code = pdf_reset_color(pdev, pis_for_hl_color, pdcolor, &pdev->saved_stroke_color, 
+			&pdev->stroke_used_process_color, &psdf_set_stroke_color_commands);
+	    if(code == 0) {
+		s = pdev->strm;
+		/* Text is emitted scaled so that the CTM is an identity matrix, the line width 
+		 * needs to be scaled to match otherwise we will get the default, or the current
+		 * width scaled by the CTM before the text, either of which would be wrong.
+		 */
+		pprintg1(s, "%g w\n", (pis->line_params.half_width * 2));
+		/* Some trickery here. We have altered the colour, text render mode and linewidth,
+		 * we don't want those to persist. By switching to a stream context we will flush the 
+		 * pending text. This has the beneficial side effect of executing a grestore. So
+		 * everything works out neatly.
+		 */
+		code = pdf_open_page(pdev, PDF_IN_STREAM);
+		return(code);
+	    }
+	}
+	/* Can only get here if any of the above steps fail, in which case we proceed to
+	 * emit the charpath as a normal path, and stroke it.
+	 */
+        code = pdf_open_page(pdev, PDF_IN_STREAM);
+    } else
+        code = pdf_open_page(pdev, PDF_IN_STREAM);
     if (code < 0)
 	return code;
     code = pdf_prepare_stroke(pdev, pis);

Modified: trunk/gs/src/gdevpdfg.c
===================================================================
--- trunk/gs/src/gdevpdfg.c	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdfg.c	2007-10-02 07:31:58 UTC (rev 8265)
@@ -286,15 +286,14 @@
 }
 
 /* Set the fill or stroke color. */
-static int
+int
 pdf_reset_color(gx_device_pdf * pdev, const gs_imager_state * pis, 
 	        const gx_drawing_color *pdc, gx_hl_saved_color * psc,
 		bool *used_process_color,
 		const psdf_set_color_commands_t *ppscc)
 {
-    int code;
+    int code = 0;
     gx_hl_saved_color temp;
-    bool process_color;
     const gs_color_space *pcs, *pcs2;
     const gs_client_color *pcc; /* fixme: not needed due to gx_hld_get_color_component. */
     cos_value_t cs_value;
@@ -304,23 +303,14 @@
 
     if (pdev->skip_colors)
 	return 0;
-    process_color = !gx_hld_save_color(pis, pdc, &temp);
+    gx_hld_save_color(pis, pdc, &temp);
     /* Since pdfwrite never applies halftones and patterns, but monitors
      * halftone/pattern IDs separately, we don't need to compare
      * halftone/pattern bodies here.
      */
     if (gx_hld_saved_color_equal(&temp, psc))
 	return 0;
-    /*
-     * In principle, we can set colors in either stream or text
-     * context.  However, since we currently enclose all text
-     * strings inside a gsave/grestore, this causes us to lose
-     * track of the color when we leave text context.  Therefore,
-     * we require stream context for setting colors.
-     */
-    code = pdf_open_page(pdev, PDF_IN_STREAM);
-    if (code < 0)
-	return code;
+
     switch (gx_hld_get_color_space_and_ccolor(pis, pdc, &pcs, &pcc)) {
 	case non_pattern_color_space:
 	    switch (gs_color_space_get_index(pcs)) {
@@ -459,6 +449,34 @@
 		      bool *used_process_color,
 		      const psdf_set_color_commands_t *ppscc)
 {
+    gx_hl_saved_color temp;
+    int code;
+
+    /* This section of code was in pdf_reset_color above, but was moved into this 
+     * routine (and below) in order to isolate the switch to a stream context. This
+     * now allows us the opportunity to write colours in any context, in particular
+     * when in a text context, by using pdf_reset_color.
+     */
+    if (pdev->skip_colors)
+	return 0;
+    gx_hld_save_color(pis, pdc, &temp);
+    /* Since pdfwrite never applies halftones and patterns, but monitors
+     * halftone/pattern IDs separately, we don't need to compare
+     * halftone/pattern bodies here.
+     */
+    if (gx_hld_saved_color_equal(&temp, psc))
+	return 0;
+    /*
+     * In principle, we can set colors in either stream or text
+     * context.  However, since we currently enclose all text
+     * strings inside a gsave/grestore, this causes us to lose
+     * track of the color when we leave text context.  Therefore,
+     * we require stream context for setting colors.
+     */
+    code = pdf_open_page(pdev, PDF_IN_STREAM);
+    if (code < 0)
+	return code;
+
     return pdf_reset_color(pdev, pis, pdc, psc, used_process_color, ppscc);
 }
 int
@@ -468,8 +486,31 @@
 		   const psdf_set_color_commands_t *ppscc)
 {
     gx_drawing_color dcolor;
+    gx_hl_saved_color temp;
+    int code;
 
     set_nonclient_dev_color(&dcolor, color);
+
+    if (pdev->skip_colors)
+	return 0;
+    gx_hld_save_color(NULL, &dcolor, &temp);
+    /* Since pdfwrite never applies halftones and patterns, but monitors
+     * halftone/pattern IDs separately, we don't need to compare
+     * halftone/pattern bodies here.
+     */
+    if (gx_hld_saved_color_equal(&temp, psc))
+	return 0;
+    /*
+     * In principle, we can set colors in either stream or text
+     * context.  However, since we currently enclose all text
+     * strings inside a gsave/grestore, this causes us to lose
+     * track of the color when we leave text context.  Therefore,
+     * we require stream context for setting colors.
+     */
+    code = pdf_open_page(pdev, PDF_IN_STREAM);
+    if (code < 0)
+	return code;
+
     return pdf_reset_color(pdev, NULL, &dcolor, psc, used_process_color, ppscc);
 }
 

Modified: trunk/gs/src/gdevpdfg.h
===================================================================
--- trunk/gs/src/gdevpdfg.h	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdfg.h	2007-10-02 07:31:58 UTC (rev 8265)
@@ -126,6 +126,10 @@
 		    bool *fill_used_process_color, bool *stroke_used_process_color);
 
 /* Set the fill or stroke color. */
+int pdf_reset_color(gx_device_pdf * pdev, const gs_imager_state * pis, 
+	        const gx_drawing_color *pdc, gx_hl_saved_color * psc,
+		bool *used_process_color,
+		const psdf_set_color_commands_t *ppscc);
 /* pdecolor is &pdev->fill_color or &pdev->stroke_color. */
 int pdf_set_pure_color(gx_device_pdf * pdev, gx_color_index color,
 		   gx_hl_saved_color * psc,

Modified: trunk/gs/src/gdevpdfx.h
===================================================================
--- trunk/gs/src/gdevpdfx.h	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdfx.h	2007-10-02 07:31:58 UTC (rev 8265)
@@ -381,6 +381,7 @@
     bool		accumulating_a_global_object;
     pdf_resource_t      *pres_soft_mask_dict;
     gs_const_string		objname;
+    int			last_charpath_op;
 } pdf_substream_save;
 
 #define private_st_pdf_substream_save()\
@@ -650,6 +651,7 @@
     gs_const_string objname;
     int OPDFRead_procset_length;      /* PS2WRITE only. */
     void *find_resource_param; /* WARNING : not visible for garbager. */
+    int last_charpath_op; /* true or false state of last charpath */
 };
 
 #define is_in_page(pdev)\

Modified: trunk/gs/src/gdevpdti.c
===================================================================
--- trunk/gs/src/gdevpdti.c	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdti.c	2007-10-02 07:31:58 UTC (rev 8265)
@@ -601,6 +601,7 @@
     pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object;
     pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict;
     pdev->sbstack[sbstack_ptr].objname = pdev->objname;
+    pdev->sbstack[sbstack_ptr].last_charpath_op = pdev->last_charpath_op;
     pdev->skip_colors = false;
     pdev->charproc_just_accumulated = false;
     pdev->pres_soft_mask_dict = NULL;
@@ -612,6 +613,7 @@
     pdev->font3 = 0;
     pdev->context = PDF_IN_STREAM;
     pdev->accumulating_substream_resource = pres;
+    pdev->last_charpath_op = 0;
     pdf_reset_graphics(pdev);
     *ppres = pres;
     return 0;
@@ -660,6 +662,7 @@
     pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object;
     pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict;
     pdev->objname = pdev->sbstack[sbstack_ptr].objname;
+    pdev->last_charpath_op = pdev->sbstack[sbstack_ptr].last_charpath_op;
     pdev->sbstack_depth = sbstack_ptr;
     code1 = pdf_restore_viewer_state(pdev, NULL);
     if (code1 < 0 && code >= 0)

Modified: trunk/gs/src/gdevpdts.c
===================================================================
--- trunk/gs/src/gdevpdts.c	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdts.c	2007-10-02 07:31:58 UTC (rev 8265)
@@ -21,6 +21,7 @@
 #include "gdevpdtx.h"
 #include "gdevpdtf.h"		/* for pdfont->FontType */
 #include "gdevpdts.h"
+#include "gdevpdtt.h"
 
 /* ================ Types and structures ================ */
 
@@ -653,3 +654,111 @@
     pts->out_pos.y += wy;
     return 0;
 }
+
+/* Check a new piece of charpath text to see if its safe to combine
+ * with a previous text operation using text rendering modes.
+ */
+bool pdf_compare_text_state_for_charpath(pdf_text_state_t *pts, gx_device_pdf *pdev, 
+					 gs_imager_state *pis, gs_font *font, 
+					 const gs_text_params_t *text)
+{
+    int code;
+    float size;
+    gs_matrix smat, tmat;
+    struct pdf_font_resource_s *pdfont;
+
+    /* check to ensure the new text has the same length as the saved text */
+    if(text->size != pts->buffer.count_chars)
+	return(false);
+
+    if(font->FontType == ft_user_defined)
+	return(false);
+
+    /* check to ensure the new text has the same data as the saved text */
+    if(memcmp(text->data.bytes, &pts->buffer.chars, text->size))
+	return(false);
+
+    /* See if the same font is in use by checking the attahced pdfont resource for
+     * the currrent font and comparing with the saved text state
+     */
+    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
+    if(code < 0)
+	return(false);
+
+    if(!pdfont || pdfont != pts->in.pdfont)
+	return(false);
+
+    /* Check to see the new text starts at the same point as the saved text. 
+     * NB! only check 2 decimal places, allow some slack in the match. This
+     * still may prove to be too tight a requirement.
+     */
+    if((int)(pts->start.x * 100) != (int)(pis->current_point.x * 100) || 
+	(int)(pts->start.y * 100) != (int)(pis->current_point.y * 100))
+	return(false);
+
+    size = pdf_calculate_text_size(pis, pdfont, &font->FontMatrix, &smat, &tmat, font, pdev);
+
+    /* Finally, check the calculated size against the size stored in
+     * the text state.
+     */
+    if(size != pts->in.size)
+	return(false);
+
+    return(true);
+}
+
+/* Add a render mode to the rendering mode of the current text.
+ * mode 0 = fill
+ * mode 1 = stroke
+ * mode 2 = clip
+ * If the modes are not compatible returns 0. NB currently only
+ * a stroke rendering mode is supported.
+ */
+int pdf_modify_text_render_mode(pdf_text_state_t *pts, int render_mode)
+{
+    switch (pts->in.render_mode) {
+	case 0:
+	    if (render_mode == 1) {
+		pts->in.render_mode = 2;
+		return(1);
+	    }
+	    break;
+	case 1:
+	    if (render_mode == 1) 
+		return(1);
+	    break;
+	case 2:
+	    if (render_mode == 1) 
+		return(1);
+	    break;
+	case 3:
+	    if (render_mode == 1) {
+	        pts->in.render_mode = 1;
+		return(1);
+	    }
+	    break;
+	case 4:
+	    if (render_mode == 1) {
+	        pts->in.render_mode = 6;
+		return(1);
+	    }
+	    break;
+	case 5:
+	    if (render_mode == 1) 
+		return(1);
+	    break;
+        case 6:
+	    if (render_mode == 1) 
+		return(1);
+	    break;
+	case 7:
+	    if (render_mode == 1) {
+	        pts->in.render_mode = 5;
+		return(1);
+	    }
+	    break;
+	default:
+	    break;
+    }
+    return(0);
+}

Modified: trunk/gs/src/gdevpdts.h
===================================================================
--- trunk/gs/src/gdevpdts.h	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdts.h	2007-10-02 07:31:58 UTC (rev 8265)
@@ -125,4 +125,10 @@
 int pdf_append_chars(gx_device_pdf * pdev, const byte * str, uint size,
 		     floatp wx, floatp wy, bool nobreak);
 
+bool pdf_compare_text_state_for_charpath(pdf_text_state_t *pts, gx_device_pdf *pdev, 
+			     gs_imager_state *pis, gs_font *font, 
+			     const gs_text_params_t *text);
+
+int pdf_modify_text_render_mode(pdf_text_state_t *pts, int render_mode);
+
 #endif /* gdevpdts_INCLUDED */

Modified: trunk/gs/src/gdevpdtt.c
===================================================================
--- trunk/gs/src/gdevpdtt.c	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdtt.c	2007-10-02 07:31:58 UTC (rev 8265)
@@ -40,6 +40,7 @@
 #include "gdevpdtt.h"
 #include "gdevpdti.h"
 #include "gxhldevc.h"
+#include "gzpath.h"
 
 /* ================ Text enumerator ================ */
 
@@ -336,6 +337,12 @@
 	pdf_current_page(pdev)->text_rotation.counts[i] += text->size;
     }
 
+    pdev->last_charpath_op = 0;
+    if ((text->operation & TEXT_DO_ANY_CHARPATH) && !path0->first_subpath) {
+	if(pdf_compare_text_state_for_charpath(pdev->text->text_state, pdev, pis, font, text))
+	    pdev->last_charpath_op = text->operation & TEXT_DO_ANY_CHARPATH;
+    }
+
     if (font->FontType == ft_user_defined &&
 	(text->operation & TEXT_DO_NONE) && (text->operation & TEXT_RETURN_WIDTH)) {
 	/* This is stringwidth, see gx_default_text_begin.
@@ -1892,25 +1899,17 @@
     }
     return 0;
 }
-int
-pdf_update_text_state(pdf_text_process_state_t *ppts,
-		      const pdf_text_enum_t *penum,
-		      pdf_font_resource_t *pdfont, const gs_matrix *pfmat)
+
+float pdf_calculate_text_size(gs_imager_state *pis, pdf_font_resource_t *pdfont, 
+			      const gs_matrix *pfmat, gs_matrix *smat, gs_matrix *tmat,
+			      gs_font *font, gx_device_pdf *pdev)
 {
-    gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev;
-    gs_font *font = penum->current_font;
-    gs_fixed_point cpt;
-    gs_matrix orig_matrix, smat, tmat;
+    gs_matrix orig_matrix;
     double
 	sx = pdev->HWResolution[0] / 72.0,
 	sy = pdev->HWResolution[1] / 72.0;
     float size;
-    float c_s = 0, w_s = 0;
-    int mask = 0;
-    int code = gx_path_current_point(penum->path, &cpt);
 
-    if (code < 0)
-	return code;
 
     /* Get the original matrix of the base font. */
 
@@ -1937,21 +1936,43 @@
 
     /* Compute the scaling matrix and combined matrix. */
 
-    gs_matrix_invert(&orig_matrix, &smat);
-    gs_matrix_multiply(&smat, pfmat, &smat);
-    tmat = ctm_only(penum->pis);
-    tmat.tx = tmat.ty = 0;
-    gs_matrix_multiply(&smat, &tmat, &tmat);
+    gs_matrix_invert(&orig_matrix, smat);
+    gs_matrix_multiply(smat, pfmat, smat);
+    *tmat = ctm_only(pis);
+    tmat->tx = tmat->ty = 0;
+    gs_matrix_multiply(smat, tmat, tmat);
 
     /* Try to find a reasonable size value.  This isn't necessary, */
     /* but it's worth a little effort. */
 
-    size = hypot(tmat.yx, tmat.yy) / sy;
+    size = hypot(tmat->yx, tmat->yy) / sy;
     if (size < 0.01)
-	size = hypot(tmat.xx, tmat.xy) / sx;
+	size = hypot(tmat->xx, tmat->xy) / sx;
     if (size < 0.01)
 	size = 1;
 
+    return(size);
+}
+
+int
+pdf_update_text_state(pdf_text_process_state_t *ppts,
+		      const pdf_text_enum_t *penum,
+		      pdf_font_resource_t *pdfont, const gs_matrix *pfmat)
+{
+    gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev;
+    gs_font *font = penum->current_font;
+    gs_fixed_point cpt;
+    gs_matrix smat, tmat;
+    float size;
+    float c_s = 0, w_s = 0;
+    int mask = 0;
+    int code = gx_path_current_point(penum->path, &cpt);
+
+    if (code < 0)
+	return code;
+
+
+    size = pdf_calculate_text_size(penum->pis, pdfont, pfmat, &smat, &tmat, penum->current_font, pdev);
     /* Check for spacing parameters we can handle, and transform them. */
 
     if (penum->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {

Modified: trunk/gs/src/gdevpdtt.h
===================================================================
--- trunk/gs/src/gdevpdtt.h	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gdevpdtt.h	2007-10-02 07:31:58 UTC (rev 8265)
@@ -322,4 +322,7 @@
 
 void adjust_first_last_char(pdf_font_resource_t *pdfont, byte *str, int size);
 
+float pdf_calculate_text_size(gs_imager_state *pis, pdf_font_resource_t *pdfont, 
+			      const gs_matrix *pfmat, gs_matrix *smat, gs_matrix *tmat,
+			      gs_font *font, gx_device_pdf *pdev);
 #endif /* gdevpdtt_INCLUDED */

Modified: trunk/gs/src/gxchar.c
===================================================================
--- trunk/gs/src/gxchar.c	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gxchar.c	2007-10-02 07:31:58 UTC (rev 8265)
@@ -1341,6 +1341,11 @@
     gs_state *pgs = penum->pgs;
     int code, rcode;
 
+    if ((penum->text.operation & TEXT_DO_FALSE_CHARPATH) || 
+	(penum->text.operation & TEXT_DO_TRUE_CHARPATH)) {
+	if (pgs->path->current_subpath)
+	    pgs->path->last_charpath_segment = pgs->path->current_subpath->last;
+    }
     if (penum->auto_release)
 	penum->procs->release((gs_text_enum_t *)penum, "show_finish");
     if (!SHOW_IS_STRINGWIDTH(penum))

Modified: trunk/gs/src/gxpath.c
===================================================================
--- trunk/gs/src/gxpath.c	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gxpath.c	2007-10-02 07:31:58 UTC (rev 8265)
@@ -105,6 +105,7 @@
     path_update_newpath(ppath);
     ppath->bbox_set = 0;
     ppath->bbox_accurate = 0;
+    ppath->last_charpath_segment = 0;
 }
 
 /*
@@ -947,6 +948,7 @@
 	gx_path_free(&path_new, "path_alloc_copy error");
 	return code;
     }
+    ppath->last_charpath_segment = 0;
     return gx_path_assign_free(ppath, &path_new);
 }
 

Modified: trunk/gs/src/gzpath.h
===================================================================
--- trunk/gs/src/gzpath.h	2007-10-01 23:02:53 UTC (rev 8264)
+++ trunk/gs/src/gzpath.h	2007-10-02 07:31:58 UTC (rev 8265)
@@ -307,6 +307,9 @@
     gs_memory_t *memory;
     gx_path_allocation_t allocation;	/* how this path was allocated */
     gx_path_segments *segments;
+    segment *last_charpath_segment; /* Used only by pdfwrite at present, 
+				     * last segment added by a charpath operation 
+				     */
     gs_fixed_rect bbox;		/* bounding box (in device space) */
     segment *box_last;		/* bbox incorporates segments */
 				/* up to & including this one */
@@ -330,9 +333,9 @@
 /* st_path should be static, but it's needed for the clip_path subclass. */
 extern_st(st_path);
 #define public_st_path()	/* in gxpath.c */\
-  gs_public_st_ptrs2(st_path, gx_path, "path",\
-    path_enum_ptrs, path_reloc_ptrs, segments, box_last)
-#define st_path_max_ptrs 2
+  gs_public_st_ptrs3(st_path, gx_path, "path",\
+    path_enum_ptrs, path_reloc_ptrs, segments, box_last, last_charpath_segment)
+#define st_path_max_ptrs 3
 
 /* Path enumeration structure */
 struct gs_path_enum_s {



More information about the gs-cvs mailing list