Bug 688007 - cjk bold fonts printed many times
Summary: cjk bold fonts printed many times
Status: RESOLVED FIXED
Alias: None
Product: Ghostscript
Classification: Unclassified
Component: PDF Writer (show other bugs)
Version: 8.50
Hardware: PC Windows XP
: P3 normal
Assignee: Ken Sharp
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-03-28 22:04 UTC by Tor Andersson
Modified: 2013-07-08 13:04 UTC (History)
6 users (show)

See Also:
Customer:
Word Size: ---


Attachments
test file with korean bold text (381.36 KB, application/postscript)
2005-03-28 22:06 UTC, Tor Andersson
Details
concept of approarch A1 (7.73 KB, application/postscript)
2007-09-17 07:15 UTC, mpsuzuki
Details
concept of approarch A2 (patch) (12.37 KB, patch)
2007-09-17 07:26 UTC, mpsuzuki
Details | Diff
concept of approarch A2 (demo document) (707 bytes, application/postscript)
2007-09-17 07:31 UTC, mpsuzuki
Details
current PDF result of approarch A1. (89.84 KB, application/pdf)
2007-09-17 07:36 UTC, mpsuzuki
Details
current PDF result of approarch A2. (80.59 KB, application/pdf)
2007-09-17 07:41 UTC, mpsuzuki
Details
sample to substitute PScript idioms (3.36 KB, application/postscript)
2007-09-17 16:47 UTC, mpsuzuki
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tor Andersson 2005-03-28 22:04:28 UTC
when converting files with gs 8.50 bold text is printed
many times with slight offsets. this happend with korean
fonts, and messes up text searching.
adobe distiller does not do this.
Comment 1 Tor Andersson 2005-03-28 22:06:01 UTC
Created attachment 1281 [details]
test file with korean bold text
Comment 2 Ray Johnston 2005-04-08 10:23:21 UTC
This file uses an PostScript procedure 'xsB' to create the 'bold' effect.

The fix for this would probably involve an Idiom to replace the xsB with
something that only emits the text once.

This happens with MS PSCRIPT5.DLL when the font doesn't have a 'Bold' flavor
and the request is for Bold (such as Impact)
Comment 3 Ray Johnston 2005-04-08 12:23:31 UTC
In fact there are several procedures that would need to be zapped with
Idioms (for the various 'show' variants). The relevant ProcSet is:

%%BeginResource: file Pscript_TextBold 5.0 0
/sB{1 copy 2 copy : sBdx 0 -M S ; : 0 sBdx -M S ; : sBdx sBdx -M S ; S}b
/asB{3 copy 3 copy 3 copy : sBdx 0 -M A ; : 0 sBdx -M A ; : sBdx sBdx -M A ; A}b
/wsB{4 copy 4 copy 4 copy : sBdx 0 -M W ; : 0 sBdx -M W ; : sBdx sBdx -M W ; W}b
/awsB {6 copy 6 copy 6 copy : sBdx 0 -M D ; : 0 sBdx -M D ; : sBdx sBdx -M D ; D}b
/xsB{ 2 copy 2 copy 2 copy : sBdx 0 -M xS ; : 0 sBdx -M xS ; : sBdx sBdx -M xS ;
xS}b
/zsB{2 copy 2 copy 2 copy : sBdx 0 -M zS ; : 0 sBdx -M zS ; : sBdx sBdx -M zS ; zS}b
/ysB{2 copy 2 copy 2 copy : sBdx 0 -M yS ; : 0 sBdx -M yS ; : sBdx sBdx -M yS ; yS}b
%%EndResource

Note: Adobe Distiller changes the xsB operation to doing the text once with "2
Tr" (fill and stroke) to do the bold. Sort of HAIRY to derive the stroke width
from the sBdx value used in the Pscript_TextBold ProcSet.

In order to determine if Adobe Distiller is using an Idiom, I zapped the
ProcSet in a test file and see what results (inserting "1 pop" in it).
This turned the original:

2 Tr
0 -1.13 TD
0.0107 Tc
[(Impa) 4.6 (c) 5.3 (t) 5.4 ( ) ] TJ

into:

0.02 -1.13 TD
0.0107 Tc
[(Impa) 4.6 (c) 5.3 (t) ] TJ
-0.02 -0.02 TD
[(Impa) 4.6 (c) 5.3 (t) ] TJ
0.02 0 TD
[(Impa) 4.6 (c) 5.3 (t) ] TJ
-0.02 0.02 TD
[(Impa) 4.6 (c) 5.3 (t) -14.6 ( ) ] TJ

which confirms that Adobe Distiller is using Idiom replacement "magic"



Comment 4 leonardo 2007-07-25 00:28:49 UTC
Passing to Alex who is our best specialist on idioms.
Comment 5 leonardo 2007-08-21 15:25:32 UTC
Passing to mpsuzuki, because we suspect he can bring a better solution from gs-
cjk.
Comment 6 Alex Cherepanov 2007-09-07 14:28:57 UTC
A few of Ghostscript developers expressed concerns that installation of
IdiomSet resources will greatly reduce Ghostscript performance.

I've run the whole regression suite on peeves with nullpage device with
10 IdiomSet resources installed. Any effect is below the natural
variation between run times. ( < 0.1%).
Comment 7 leonardo 2007-09-14 03:11:33 UTC
Bug 689310 "Offset between text and outline in pdfwrite.dev" shows a similar 
problem, which may be addressed as an idiom recognition. Feel free to pass this 
bug to ken.sharp@artifex.com .

Comment 8 mpsuzuki 2007-09-17 07:07:32 UTC
In following, I use the term "style synthesis" to call the glyphs
transformed by text graphic frameworks, like "Bold", "Italic",
"Outline", "Shadow" etc etc. 

I think this bug is NOT CJK-specific issue in technical viewpoint.
The remarkable difficulty in this issue is that the font object
nor text drawing procedure in pswrite/pdfwrite don't have
internal switches for style synthesis. In PDF, the style synthesis
for bolding is implemented by changing the graphical parameters:
"w" (setlinewidth) and "Tr" (PaintType).

In the case of PDF, style synthesis is executed in graphics
level, not in text/font level. Once the parameters are
reflected on the output device, changing current font is
insufficient to reset the style synthesis parameters.
Such method is dependent on the output device (it is very
possible that such graphical parameters cannot affect the
text rendering on some PDL).
Comment 9 mpsuzuki 2007-09-17 07:08:48 UTC
There are 2 approaches to fix the issue: how to optimize
embolden text for PDF, to avoid repeating the text which
makes the text informations ugly.

A1) Simplification by pre-synthesized Type3/CIDFontType1.

By Idiom substitution, the procedures to draw synthesized
style is substituted by the combination of simple "show" families
and Type3 or CIDFontType1 fonts whose BuildGlyph procedure
executes the style synthesis per glyph.  By using such font
with simple "show" families, repeating of text drawing can be
avoided.

advantage: this approarch is almost independent with output
device, and it's easy to proof the expected optimization.

disadvantage: the handling of CIDFontType1 in current
ghostscript pdfwrite is very primitive. The text drawn by
Type3 font can be searched, but the text drawn by CIDFontType1
is not. The current implementation collects the bitmap images
from glyph cache, pack them into Type3 fonts per 256 images.
Thus, the text information is lost. The straight-forward
embedding of CIDFontType1 is not supported. Making CJK text
drawn by Type3 or CIDFontType1 font is long awaiting feature
since gs5.5x, it may be worthful, but it will be long way.

A2) Introduction of lazy style synthesis marking (LSS-mark)
for output device driver

By Idiom substitution, the procedure to draw synthesized
style is substituted by the procedure marking the current
font as "requested to be style synthesized" and let the
output device driver to handle the marked font object.
By using marked font with smiple "show" families, repeating
of text drawing can be avoided.

advantage: this approach can utilize existing Type1/Type42/
CIDFontType0/CIDFontType1 embedding features.

disadvantage: the style synthesis result depends on the
device. We cannot proof how the embolding in pdfwrite works
via X11 device.
Comment 10 mpsuzuki 2007-09-17 07:15:26 UTC
Created attachment 3381 [details]
concept of approarch A1

A proof of concept in approarch A1. Here's no Idiom substitution,
but 3 fundamental procedures are implemented.

A1-a) /.synth_bold_basefont is a procedure to make a Type3 or
      CIDFontType1 for given Type1/3/42 and CIDFontType0/1/2.

A1-b) /.decompose_cmapped_font is a procedure to decompose
      FMapType9-Type0 font and stack the scalematrix and CMap
      dict and basefont.

A1-c) /.recompose_cmapped_font is a procedure to recompose
      Type0 font from stacked scalematrix, CMap dict and
      CIDFont.

To execute this sample implementation, Courier must be Type1
font (not TrueType emulation), and WadaMaruGo-Regular must be
CIDFontType0 (not cidfmap emulation). In this example, TrueType
based Type3 is very slow.
Comment 11 mpsuzuki 2007-09-17 07:26:16 UTC
Created attachment 3382 [details]
concept of approarch A2 (patch)

Here is a sample implementation of device-dependent
style synthesis.

If the difference of the style synthesis parameter is regarded
as so critical and the font should be registered as unique
resource (e.g. registering the marked font as /Impact,Bold,
which is different from original /Impact, although the contents
of font dicts are completely same), there will be a few problems:
the appropriate naming convention (e.g. can we guarantee the
source PS document does not define /Impact,Bold by itself?)
and the divided font cache (e.g. pdfwrite will embed 2 font
objects: /Impact and /Impact,Bold, although their contents
are completely same).
As an experiment to avoid the font resource management issue,
I deal the LSS-mark as a scaling matrix parameter. Thus,
we don't have to define/undefine new font resource per each
style synthesis. As we can do as "currentfont 36 scalefont
setfont", I designed LSS-mark can be set without definition
of font resource. In addition, the LSS-mark should not be
used by normal PostScript rendering, but the LSS-mark should
be visible and variable from PostScript space (to work with
Idiom substitution).

A2-a) gs_font structure is extended to have additional LSS
parameters for style synthesis. This bug report mentions
only embolding feature, but I introduced all the switches
described in MacOS QuickDraw (I think it's most rich), for
future completion of similar problems related to style
synthesis.

Index: src/gxfont.h
===================================================================
--- src/gxfont.h	(revision 8217)
+++ src/gxfont.h	(working copy)
@@ -365,6 +365,52 @@
     uint size;
 } gs_font_name;
 
+/* The style synthesis flag handled by output device */+typedef byte
gs_lazy_stylebit_t;
+#define GS_LAZY_BOLD		0x01 /* MacOS QuickDraw style code */
+#define GS_LAZY_ITALIC 	0x02 /* ditto */
+#define GS_LAZY_UNDERLINE	0x04 /* ditto */
+#define GS_LAZY_OUTLINE		0x08 /* ditto */
+#define GS_LAZY_SHADOW 	0x10 /* ditto */
+#define GS_LAZY_CONDENSE	0x20 /* ditto */
+#define GS_LAZY_EXTEND 	0x40 /* ditto */
+#define GS_LAZY_RESERVED	0x80 /* ditto */
+typedef struct gs_lazy_stylesynth_s {
+    gs_lazy_stylebit_t stylebit;
+    float BoldWidth;
+    float ItalicAngle;
+    float UnderlineGap, UnderlineWidth;
+    float OutlineWidth;
+    float ShadowGap, ShadowWidth;
+    float CondenseWidth;
+    float ExtendWidth;
+} gs_lazy_stylesynth_t;
+#define cmplazyBold( a, b ) \
+    ( 0 < ( (a).stylebit & GS_LAZY_BOLD ) ? (a).BoldWidth == (b).BoldWidth : 1
)
+#define cmplazyItalic( a, b ) \
+    ( 0 < ( (a).stylebit & GS_LAZY_ITALIC ) ? (a).ItalicAngle ==
(b).ItalicAngle : 1 )
+#define cmplazyUnderline( a, b ) \
+    ( 0 < ( (a).stylebit & GS_LAZY_UNDERLINE ) ? ( (a).UnderlineGap ==
(b).UnderlineGap && \
+						(a).UnderlineWidth ==
(b).UnderlineWidth ) : 1 )
+#define cmplazyOutline( a, b ) \
+    ( 0 < ( (a).stylebit & GS_LAZY_OUTLINE ) ? (a).OutlineWidth ==
(b).OutlineWidth : 1 )
+#define cmplazyShadow( a, b ) \
+    ( 0 < ( (a).stylebit & GS_LAZY_SHADOW ) ? ( (a).ShadowGap == (b).ShadowGap
&& \
+					     (a).ShadowWidth == (b).ShadowWidth
) : 1 )
+#define cmplazyCondense( a, b ) \
+    ( 0 < ( (a).stylebit & GS_LAZY_CONDENSE ) ? (a).CondenseWidth ==
(b).CondenseWidth : 1 )
+#define cmplazyExtend( a, b ) \
+    ( 0 < ( (a).stylebit & GS_LAZY_EXTEND ) ? (a).ExtendWidth ==
(b).ExtendWidth : 1 )
+#define cmplazystyle( a, b ) \
+  ( (a).stylebit == (b).stylebit && \
+	cmplazyBold( a, b ) && \
+	cmplazyItalic( a, b ) && \
+	cmplazyUnderline( a, b ) && \
+	cmplazyOutline( a, b ) && \
+	cmplazyShadow( a, b ) && \
+	cmplazyCondense( a, b ) && \
+	cmplazyExtend( a, b ) )
+
 /*
  * Define a generic font.  We include PaintType and StrokeWidth here because
  * they affect rendering algorithms outside the Type 1 font machinery.
@@ -379,6 +425,7 @@
	gs_memory_t *memory;		/* allocator for this font */\
	gs_font_dir *dir;		/* directory where registered */\
	bool is_resource;\
+	gs_lazy_stylesynth_t lazystyle; /* device dependent style synthesis */\

	gs_notify_list_t notify_list;	/* clients to notify when freeing */\
	gs_id id;			/* internal ID (no relation to UID) */\

	gs_font *base;			/* original (unscaled) base font */\

A2-b) /DefineResource in gs_res.ps & gs_cidfn.ps, /.composefont
in gs_cmap.ps are extended to insert /.LazyStyleSynth dict
which is an interface between PostScript space and LSS-mark
in gs_font.

Index: lib/gs_res.ps
===================================================================
--- lib/gs_res.ps	(revision 8217)
+++ lib/gs_res.ps	(working copy)
@@ -955,7 +955,19 @@
 /InstanceType /dicttype
 
 /DefineResource
-	{ 2 copy //definefont exch pop
+	{
+	  dup /.LazyStyleSynth known not {
+	    dup /.LazyStyleSynth 16 dict
+	       dup /useBold	 false .growput dup /BoldWidth	   0 .growput
+	       dup /useItalic	 false .growput dup /ItalicAngle   0 .growput
+	       dup /useUnderline false .growput dup /UnderlineGap  0 .growput
dup /UnderlineWidth 0 .growput
+	       dup /useOutline	 false .growput dup /OutlineWidth  0 .growput
+	       dup /useShadow	 false .growput dup /ShadowGap	   0 .growput
dup /ShadowWidth 0 .growput
+	       dup /useCondense  false .growput dup /CondenseWidth 0 .growput
+	       dup /useExtend	 false .growput dup /ExtendWidth   0 .growput
+	     .growput
+	   } if
+	  2 copy //definefont exch pop
	  /Generic /Category findresource /DefineResource get exec
	} bind
 /UndefineResource
Index: lib/gs_cidfn.ps
===================================================================
--- lib/gs_cidfn.ps	(revision 8217)
+++ lib/gs_cidfn.ps	(working copy)
@@ -349,6 +349,20 @@
   dup /PaintType known not {
      dup /PaintType 0 .growput  % CPSI does it. Adding just for CET 33_all.PS
conformity.
   } if
+  dup /.LazyStyleSynth known not {
+     currentglobal exch
+     true setglobal
+     dup /.LazyStyleSynth 16 dict
+	  dup /useBold	    false .growput dup /BoldWidth     0 .growput
+	  dup /useItalic    false .growput dup /ItalicAngle   0 .growput
+	  dup /useUnderline false .growput dup /UnderlineGap  0 .growput dup
/UnderlineWidth 0 .growput
+	  dup /useOutline   false .growput dup /OutlineWidth  0 .growput
+	  dup /useShadow    false .growput dup /ShadowGap     0 .growput dup
/ShadowWidth 0 .growput
+	  dup /useCondense  false .growput dup /CondenseWidth 0 .growput
+	  dup /useExtend    false .growput dup /ExtendWidth   0 .growput
+     .growput
+     exch setglobal
+  } if
   /Generic /Category findresource /DefineResource get exec
 } put
 % CIDFonts may be defined in CFF OpenType files.
Index: lib/gs_cmap.ps
===================================================================
--- lib/gs_cmap.ps	(revision 8217)
+++ lib/gs_cmap.ps	(working copy)
@@ -73,6 +73,7 @@
     /FontMatrix matrix def
     /FontName 3 index def
     CMap /WMode .knownget { /WMode exch def } if
+    FDepVector { /.LazyStyleSynth .knownget { /.LazyStyleSynth exch def exit }
if } forall
     /FontType 0 def
   pop pop currentdict end 
 } bind odef
@@ -81,6 +82,7 @@
 % the "PostScript Language Reference Manual Supplement".
 /composefont { 	% <name> <cmap|cmapname> <fonts> composefont <font>
   .composefontdict /Font defineresource
+  dup /.LazyStyleSynth .knownget { { .setlazystyleparam } forall } if
 } bind def
 
 % ---------------- CMap operators ---------------- %


A2-c) New operator ".setlazystyleparam" is introduced
to control /.LazyStyleSynth dict and update the internal
LSS-mark in gs_font.

Index: src/zfont.c
===================================================================
--- src/zfont.c (revision 8217)
+++ src/zfont.c (working copy)
@@ -25,8 +25,10 @@
 #include "iddict.h"
 #include "igstate.h"
 #include "iname.h"		/* for name_mark_index */
+#include "inamedef.h"
 #include "isave.h"
 #include "store.h"
+#include "string_.h"
 #include "ivmspace.h"
 #include "gscencs.h"
 
@@ -209,6 +211,109 @@
 }
 
 
+private int
+sync_lazystyleparam(gs_font *pfont, const ref *lazystyleparam)
+{
+    int code;
+    ref *pvalue;
+
+#define SET_LAZY_STYLE_BIT( keyname, bitmacro ) \
+    code = dict_find_string(lazystyleparam, (keyname), &pvalue); \
+    if (code < 0) \
+	 return code; \
+    else if (t_boolean == r_type(pvalue) && pvalue->value.boolval) \
+	 pfont->lazystyle.stylebit |= (bitmacro); \
+    else \
+	 pfont->lazystyle.stylebit &= ~(bitmacro);
+
+    SET_LAZY_STYLE_BIT( "useBold",	 GS_LAZY_BOLD );
+    SET_LAZY_STYLE_BIT( "useItalic",	 GS_LAZY_ITALIC );
+    SET_LAZY_STYLE_BIT( "useUnderline", GS_LAZY_UNDERLINE );
+    SET_LAZY_STYLE_BIT( "useOutline",	 GS_LAZY_OUTLINE );
+    SET_LAZY_STYLE_BIT( "useShadow",	 GS_LAZY_SHADOW );
+    SET_LAZY_STYLE_BIT( "useCondense",  GS_LAZY_CONDENSE );
+    SET_LAZY_STYLE_BIT( "useExtend",	 GS_LAZY_EXTEND );
+
+#undef SET_LAZY_STYLE_BIT
+
+#define SET_LAZY_STYLE_FLOAT_MEMBER( keyname, fmember ) \
+    code = dict_find_string(lazystyleparam, (keyname), &pvalue); \
+    if (code < 0) \
+	 return code; \
+    else if (t_real == r_type(pvalue)) \
+	 pfont->lazystyle.fmember = pvalue->value.realval; \
+    else \
+	 pfont->lazystyle.fmember = 0;
+
+    SET_LAZY_STYLE_FLOAT_MEMBER( "BoldWidth",	    BoldWidth );
+    SET_LAZY_STYLE_FLOAT_MEMBER( "ItalicAngle",    ItalicAngle );
+    SET_LAZY_STYLE_FLOAT_MEMBER( "UnderlineGap",   UnderlineGap );
+    SET_LAZY_STYLE_FLOAT_MEMBER( "UnderlineWidth", UnderlineWidth );
+    SET_LAZY_STYLE_FLOAT_MEMBER( "ShadowGap",	    ShadowGap );
+    SET_LAZY_STYLE_FLOAT_MEMBER( "ShadowWidth",    ShadowWidth );
+    SET_LAZY_STYLE_FLOAT_MEMBER( "CondenseWidth",  CondenseWidth );
+    SET_LAZY_STYLE_FLOAT_MEMBER( "ExtendWidth",    ExtendWidth );
+
+#undef SET_LAZY_STYLE_FLOAT_MEMBER
+
+    return 0;
+}
+
+/* <font> <key> <val> .setlazystyleparam <font> */
+private int
+zsetlazystyleparam(i_ctx_t *i_ctx_p)
+{
+    os_ptr op_value = osp;
+    os_ptr op_key   = op_value - 1;
+    os_ptr op_font  = op_key - 1;
+    gs_font *pfont;
+    ref *lazystyleparam, *pvalue;
+    bool is_boolean_key;
+    int code;
+
+    code = font_param(op_font, &pfont);
+    if (code < 0)
+	return code;
+
+    if (dict_find_string(op_font, ".LazyStyleSynth", &lazystyleparam) <= 0)
+	 return e_invalidfont;
+
+    if (t_name != r_type(op_key))
+	 return e_typecheck;
+
+    code = dict_find(lazystyleparam, op_key, &pvalue);
+    if (code < 0)
+	return code;
+
+    /* "/useXXX" is assumed to be boolean, others are numericals */
+    name_string_ref(imemory, op_key, op_key);
+    if (0 == strncmp(op_key->value.const_bytes, "use", 3))
+	 is_boolean_key = true;
+    else
+	 is_boolean_key = false;
+    name_from_string(imemory, op_key, op_key);
+
+    /* value should be boolean or integer or real */
+    if (is_boolean_key) {
+	 if (t_boolean != r_type(op_value))
+	     return e_typecheck;
+    } else if (t_integer == r_type(op_value))
+	 make_real(op_value, (float)op_value->value.intval);
+    else if (t_real != r_type(op_value))
+	 return e_typecheck;
+
+    code = dict_put(lazystyleparam, op_key, op_value, NULL);
+    if (code < 0)
+	return code;
++    code = sync_lazystyleparam(pfont, lazystyleparam);
+    if (code < 0)
+	return code;
+
+    pop(2);
+    return 0;
+}
+
 /* <Decoding> .setupUnicodeDecoder - */
 private int
 zsetupUnicodeDecoder(i_ctx_t *i_ctx_p)
@@ -237,6 +342,7 @@
     {"1setcacheparams", zsetcacheparams},
     {"0currentcacheparams", zcurrentcacheparams},
     {"1.registerfont", zregisterfont},
+    {"3.setlazystyleparam", zsetlazystyleparam},
     {"1.setupUnicodeDecoder", zsetupUnicodeDecoder},
     op_def_end(zfont_init)
 };

A2-d) The font caching system is changed to care
the difference of LSS-mark. If it doesn't care, the cached
image of normal font is reused for the LSS-marked font.

Index: src/gsfont.c
===================================================================
--- src/gsfont.c	(revision 8217)
+++ src/gsfont.c	(working copy)
@@ -486,6 +486,7 @@
	for (; pf_out != 0; prev = pf_out, pf_out = pf_out->next)
	    if (pf_out->FontType == pfont->FontType &&
		pf_out->base == pfont->base &&
+		cmplazystyle(pf_out->lazystyle, pfont->lazystyle) &&
		pf_out->FontMatrix.xx == newmat.xx &&
		pf_out->FontMatrix.xy == newmat.xy &&
		pf_out->FontMatrix.yx == newmat.yx &&


A2-e) If the font has the LSS-mark for bolding, pdfwrite
insert setlinewidth and PaintType operator.

Index: src/gdevpdts.h
===================================================================
--- src/gdevpdts.h	(revision 8217)
+++ src/gdevpdts.h	(working copy)
@@ -36,6 +36,9 @@
  * (and, in the case of text positioning, how) to emit PDF commands to
  * set them in the output.
  */
+typedef struct pdf_text_state_values_stylesynth_s {
+    float linewidth;+} pdf_text_state_values_stylesynth_t; 
 typedef struct pdf_text_state_values_s {
     float character_spacing;	/* Tc */
     pdf_font_resource_t *pdfont; /* for Tf */
@@ -49,6 +52,8 @@
     gs_matrix matrix;		/* Tm et al */
     int render_mode;		/* Tr */
     float word_spacing;		/* Tw */
+    /* The parameters for style synthesis: line width etc */
+    pdf_text_state_values_stylesynth_t stylesynth_params;
 } pdf_text_state_values_t;
 #define TEXT_STATE_VALUES_DEFAULT\
     0, 			/* character_spacing */\
Index: src/gdevpdtt.c
===================================================================
--- src/gdevpdtt.c	(revision 8217)
+++ src/gdevpdtt.c	(working copy)
@@ -1986,6 +1986,13 @@
     ppts->values.word_spacing = w_s;
     ppts->font = font;
 
+    ppts->values.stylesynth_params.linewidth = 0;
+    /* under non-default rendering mode, the computation of appropriate
render_mode is difficult */
+    if (0 == ppts->values.render_mode && 0 != (GS_LAZY_BOLD &
penum->current_font->lazystyle.stylebit)) {
+	 ppts->values.render_mode = 2;
+	 ppts->values.stylesynth_params.linewidth =
penum->current_font->lazystyle.BoldWidth * size;
+    }
+
     code = pdf_set_text_process_state(pdev, (const gs_text_enum_t *)penum,
				      ppts);
     return (code < 0 ? code : mask);
Index: src/gdevpdts.c
===================================================================
--- src/gdevpdts.c	(revision 8217)
+++ src/gdevpdts.c	(working copy)
@@ -472,6 +472,10 @@
	    return code;
     }
 
+    if (0 != pts->in.render_mode && 0 < pts->in.stylesynth_params.linewidth) {

+	pprintg1(s, "%g w 1 M\n", pts->in.stylesynth_params.linewidth);
+    }
+
     if (pts->out.render_mode != pts->in.render_mode) {
	pprintg1(s, "%g Tr\n", pts->in.render_mode);
	pts->out.render_mode = pts->in.render_mode;
Comment 12 mpsuzuki 2007-09-17 07:31:17 UTC
Created attachment 3383 [details]
concept of approarch A2 (demo document)

Sample program using LSS-mark implemented by previous patch
Comment 13 mpsuzuki 2007-09-17 07:36:13 UTC
Created attachment 3384 [details]
current PDF result of approarch A1.

current PDF result of approarch A1.
Roman text is drawn once, but CJK text is drawn as graphics.

q 0.1 0 0 0.1 0 0 cm
/R7 gs
0 G
0 g
q
10 0 0 10 0 0 cm BT
/R8 32 Tf
1 0 0 1 10 700 Tm
(this is normal /Courier)Tj
/R27 1 Tf
40 TL
(this is /Courier,Bold)'
/R28 32 Tf
60 TL
(<E5><92><8C><E7><94><B0><E7><A0><94><E4><B8><B8><E3><82><B4><E3><82><B7><E3><83><83><E3><82><AF>)'

ET
Q
32 w
280.48 5554.72 m
280.48 5540.64 292 5529.12 306.398 5529.12 c
353.762 5529.12 l
...
Comment 14 mpsuzuki 2007-09-17 07:41:28 UTC
Created attachment 3385 [details]
current PDF result of approarch A2.

current PDF result of approarch A2 is better for trivial & healthy input.

q 0.1 0 0 0.1 0 0 cm
/R7 gs
0 G
0 g
q
10 0 0 10 0 0 cm BT
0 w
/R8 20 Tf
1 0 0 1 10 400 Tm
(Courier)Tj
25 TL
1 w 1 M
2 Tr
(Courier,Bold)'
/R12 20 Tf
75 TL
0 Tr
(<E5><92><8C><E7><94><B0><E7><A0><94><E4><B8><B8><E3><82><B4><E3><82><B7><E3><83><83><E3><82><AF>)'

25 TL
1 w 1 M
2 Tr
(<E5><92><8C><E7><94><B0><E7><A0><94><E4><B8><B8><E3><82><B4><E3><82><B7><E3><83><83><E3><82><AF><EF><BC><8C><EF><BC><A2><EF><BD><8F><EF>

<BD><8C><EF><BD><84>)'
ET
Q
Q
Comment 15 mpsuzuki 2007-09-17 07:43:56 UTC
Left issues of approach A2 patch:

when pdfwrite receives a failure in rendering a text and
regard the text cannot be embed as a combination of normal
font & coded text, pdfwrite falls back to "default" rendering
which drawing a text by Type3 font of cached images (if
font cache is available) or draw vector graphics of extracted
glyph paths (if font cache is unavailable). The LSS-mark
should be reflected in such case. Yet I've not finished that.

In the case of bitmap Type3 fallback, it's difficult to embold
the glyph by setlinewidth and PaintType, because the glyph
data is bitmap which setlinewidth/PaintType does not affect.
Some embolding hook should be inserted into /BuildGlyph
procedure of original font to obtain embolden glyph cache,
but it's not easy. In the case of vector graphics fallback,
the setlinewidth/PaintType may work.

Comment 16 Ken Sharp 2007-09-17 08:33:06 UTC
Wow, a sudden flurry of activity :-)

I have been exchanging email with Igor over this one, and I think a better
approach is the one taken by Adobe. This is a two step refinement, and depends
in part on other work which I am already implementing for a different issue.

From Ray's original investigation, and examination of the behaviour of Acrobat,
what Distiller seems to do is:

1) Convert the multiple 'show' operations into a single step, using Idiom
recognition. This single step does the equivalent of '(text) show (text)
charpath x setlinewidth stroke.

2) Internally convert the sequence show/charpath/stroke or charpath/fill/stroke
into a '2 Tr (text) show' operation. '2 Tr' means stroke *and* fill the text.

The emboldening is done by stroking the charpath with a wider line width, this
seems (from Ray's work) to be done by an idiom. Since Adobe clearly feel this is
adequate, I think we should follow their lead and do the same.

conversion of charpath/stroke is an issue I'm already looking at, for bug
#689310. In this case the stroke is not co-incident with the text, so we need to
do this heuristic conversion to a 'show' with a different PDF text rendering rule.

If we idiom recognise the Microsoft artificial bold operators, replace them with
charpath stroke, and put that together with the work I'm already doing, then we
should see a good result, I believe.

This should (eventually) lead to just one set of text in the output, the same as
the Adobe result. We don't have to mess about with type 3 fonts and custom
BuildGlyph procedures, and we don't have to rely on the device to take special
action.
Comment 17 leonardo 2007-09-17 11:22:01 UTC
Ken and me agree that this issue is not related to CJK and must be passed to 
Ken. Dear mpsuzuki please change the assignment if you have no objection. If 
you have an objection, please let us know.
Comment 18 leonardo 2007-09-17 12:49:00 UTC
Ken and me discussed it more and we believe it should be passed to Alex for 
writing an idiom with applying a stroked font. I mean fill the normal text and 
then stroke it with appropriate linewidth for enbolding. Converting it to 
2 .settextrenderingmode should be a next step for high level devices only, 
which to be addressed to bug 689310 assigned to Ken.

Dear mpsuzuki please let us know if you've got an objection for unassigning 
this bug from you.
Comment 19 mpsuzuki 2007-09-17 16:47:20 UTC
Created attachment 3390 [details]
sample to substitute PScript idioms

Here's IdiomRecognition sample.

  /sB [
     { % original PScript idiom
	1 copy 2 copy
	gsave sBdx    0 rmoveto show grestore
	gsave	 0 sBdx rmoveto show grestore
	gsave sBdx sBdx rmoveto show grestore
	show
     } bind
     { % idiom to substitute
       (known idiom /sB /sBdx=) print sBdx == flush
       gsave 0.18 sBdx mul setlinewidth show grestore
     } bind
  ]

Please change "0.18 sBdx mul setlinewidth" phrase to
appropriate procedure for embolding.
Comment 20 mpsuzuki 2007-09-17 16:59:14 UTC
Yet I've not accepted this bug, so I have no objection to
reassign this bug to other experts. I expect the preparation
of a room to enhance for outline/shadow style synthesis.
Now I pass this bug to Alex.
Comment 21 Marcos H. Woehrmann 2008-03-06 12:39:44 UTC
This is no longer a customer bug, since the reporter is no longer a customer.
Comment 22 Ken Sharp 2013-07-08 13:04:11 UTC
commmit 34e2ae40bff4d288da83dcd739e50287bf7c3c2e fixes this for me.