xref: /plan9-contrib/sys/src/cmd/gs/src/gdevpdtt.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1*593dc095SDavid du Colombier /* Copyright (C) 2002 Aladdin Enterprises.  All rights reserved.
2*593dc095SDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
5*593dc095SDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
9*593dc095SDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15*593dc095SDavid du Colombier */
16*593dc095SDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevpdtt.c,v 1.104 2005/10/12 08:16:50 leonardo Exp $ */
18*593dc095SDavid du Colombier /* Text processing for pdfwrite. */
19*593dc095SDavid du Colombier #include "math_.h"
20*593dc095SDavid du Colombier #include "string_.h"
21*593dc095SDavid du Colombier #include "gx.h"
22*593dc095SDavid du Colombier #include "gserrors.h"
23*593dc095SDavid du Colombier #include "gscencs.h"
24*593dc095SDavid du Colombier #include "gscedata.h"
25*593dc095SDavid du Colombier #include "gsmatrix.h"
26*593dc095SDavid du Colombier #include "gzstate.h"
27*593dc095SDavid du Colombier #include "gxfcache.h"		/* for orig_fonts list */
28*593dc095SDavid du Colombier #include "gxfont.h"
29*593dc095SDavid du Colombier #include "gxfont0.h"
30*593dc095SDavid du Colombier #include "gxfcid.h"
31*593dc095SDavid du Colombier #include "gxfcopy.h"
32*593dc095SDavid du Colombier #include "gxfcmap.h"
33*593dc095SDavid du Colombier #include "gxpath.h"		/* for getting current point */
34*593dc095SDavid du Colombier #include "gxchar.h"
35*593dc095SDavid du Colombier #include "gxstate.h"
36*593dc095SDavid du Colombier #include "gdevpdfx.h"
37*593dc095SDavid du Colombier #include "gdevpdfg.h"
38*593dc095SDavid du Colombier #include "gdevpdtx.h"
39*593dc095SDavid du Colombier #include "gdevpdtd.h"
40*593dc095SDavid du Colombier #include "gdevpdtf.h"
41*593dc095SDavid du Colombier #include "gdevpdts.h"
42*593dc095SDavid du Colombier #include "gdevpdtt.h"
43*593dc095SDavid du Colombier #include "gdevpdti.h"
44*593dc095SDavid du Colombier #include "gxhldevc.h"
45*593dc095SDavid du Colombier 
46*593dc095SDavid du Colombier /* ================ Text enumerator ================ */
47*593dc095SDavid du Colombier 
48*593dc095SDavid du Colombier /* GC descriptor */
49*593dc095SDavid du Colombier private_st_pdf_text_enum();
50*593dc095SDavid du Colombier 
51*593dc095SDavid du Colombier /* Define the auxiliary procedures for text processing. */
52*593dc095SDavid du Colombier private int
pdf_text_resync(gs_text_enum_t * pte,const gs_text_enum_t * pfrom)53*593dc095SDavid du Colombier pdf_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
54*593dc095SDavid du Colombier {
55*593dc095SDavid du Colombier     pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
56*593dc095SDavid du Colombier 
57*593dc095SDavid du Colombier     if ((pte->text.operation ^ pfrom->text.operation) & ~TEXT_FROM_ANY)
58*593dc095SDavid du Colombier 	return_error(gs_error_rangecheck);
59*593dc095SDavid du Colombier     if (penum->pte_default) {
60*593dc095SDavid du Colombier 	int code = gs_text_resync(penum->pte_default, pfrom);
61*593dc095SDavid du Colombier 
62*593dc095SDavid du Colombier 	if (code < 0)
63*593dc095SDavid du Colombier 	    return code;
64*593dc095SDavid du Colombier     }
65*593dc095SDavid du Colombier     pte->text = pfrom->text;
66*593dc095SDavid du Colombier     gs_text_enum_copy_dynamic(pte, pfrom, false);
67*593dc095SDavid du Colombier     return 0;
68*593dc095SDavid du Colombier }
69*593dc095SDavid du Colombier private bool
pdf_text_is_width_only(const gs_text_enum_t * pte)70*593dc095SDavid du Colombier pdf_text_is_width_only(const gs_text_enum_t *pte)
71*593dc095SDavid du Colombier {
72*593dc095SDavid du Colombier     const pdf_text_enum_t *const penum = (const pdf_text_enum_t *)pte;
73*593dc095SDavid du Colombier 
74*593dc095SDavid du Colombier     if (penum->pte_default)
75*593dc095SDavid du Colombier 	return gs_text_is_width_only(penum->pte_default);
76*593dc095SDavid du Colombier     return false;
77*593dc095SDavid du Colombier }
78*593dc095SDavid du Colombier private int
pdf_text_current_width(const gs_text_enum_t * pte,gs_point * pwidth)79*593dc095SDavid du Colombier pdf_text_current_width(const gs_text_enum_t *pte, gs_point *pwidth)
80*593dc095SDavid du Colombier {
81*593dc095SDavid du Colombier     const pdf_text_enum_t *const penum = (const pdf_text_enum_t *)pte;
82*593dc095SDavid du Colombier 
83*593dc095SDavid du Colombier     if (penum->pte_default)
84*593dc095SDavid du Colombier 	return gs_text_current_width(penum->pte_default, pwidth);
85*593dc095SDavid du Colombier     return_error(gs_error_rangecheck); /* can't happen */
86*593dc095SDavid du Colombier }
87*593dc095SDavid du Colombier private int
pdf_text_set_cache(gs_text_enum_t * pte,const double * pw,gs_text_cache_control_t control)88*593dc095SDavid du Colombier pdf_text_set_cache(gs_text_enum_t *pte, const double *pw,
89*593dc095SDavid du Colombier 		   gs_text_cache_control_t control)
90*593dc095SDavid du Colombier {
91*593dc095SDavid du Colombier     pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
92*593dc095SDavid du Colombier     gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
93*593dc095SDavid du Colombier 
94*593dc095SDavid du Colombier     switch (control) {
95*593dc095SDavid du Colombier     case TEXT_SET_CHAR_WIDTH:
96*593dc095SDavid du Colombier     case TEXT_SET_CACHE_DEVICE:
97*593dc095SDavid du Colombier 	gs_distance_transform(pw[0], pw[1], &ctm_only(pte->pis), &pdev->char_width);
98*593dc095SDavid du Colombier 	break;
99*593dc095SDavid du Colombier     case TEXT_SET_CACHE_DEVICE2:
100*593dc095SDavid du Colombier 	/*
101*593dc095SDavid du Colombier 	 * pdev->char_width is used with synthesized Type 3 fonts only.
102*593dc095SDavid du Colombier 	 * Since they are simple fonts, we only need the horisontal
103*593dc095SDavid du Colombier 	 * width for Widths array. Therefore we don't check
104*593dc095SDavid du Colombier 	 * gs_rootfont(pgs)->WMode and don't use pw[6:7].
105*593dc095SDavid du Colombier 	 */
106*593dc095SDavid du Colombier 	gs_distance_transform(pw[0], pw[1], &ctm_only(pte->pis), &pdev->char_width);
107*593dc095SDavid du Colombier 	if (penum->cdevproc_callout) {
108*593dc095SDavid du Colombier 	    memcpy(penum->cdevproc_result, pw, sizeof(penum->cdevproc_result));
109*593dc095SDavid du Colombier 	    return 0;
110*593dc095SDavid du Colombier 	}
111*593dc095SDavid du Colombier 	break;
112*593dc095SDavid du Colombier     default:
113*593dc095SDavid du Colombier 	return_error(gs_error_rangecheck);
114*593dc095SDavid du Colombier     }
115*593dc095SDavid du Colombier     if (penum->current_font->FontType == ft_user_defined &&
116*593dc095SDavid du Colombier 	    penum->orig_font->FontType != ft_composite &&
117*593dc095SDavid du Colombier 	    penum->outer_CID == GS_NO_GLYPH &&
118*593dc095SDavid du Colombier 	    !(penum->pte_default->text.operation & TEXT_DO_CHARWIDTH)) {
119*593dc095SDavid du Colombier 	int code;
120*593dc095SDavid du Colombier 	gs_font *font = penum->orig_font;
121*593dc095SDavid du Colombier 	gs_char ch;
122*593dc095SDavid du Colombier 	gs_glyph glyph;
123*593dc095SDavid du Colombier 	gs_const_string gnstr;
124*593dc095SDavid du Colombier 
125*593dc095SDavid du Colombier 	if (penum->text.operation & TEXT_FROM_SINGLE_GLYPH) {
126*593dc095SDavid du Colombier 	    byte buf[1];
127*593dc095SDavid du Colombier 	    int char_code_length;
128*593dc095SDavid du Colombier 
129*593dc095SDavid du Colombier 	    glyph = pte->text.data.d_glyph;
130*593dc095SDavid du Colombier 	    code = pdf_encode_glyph((gs_font_base *)font, glyph,
131*593dc095SDavid du Colombier 			buf, sizeof(buf), &char_code_length);
132*593dc095SDavid du Colombier 	    if (code < 0) {
133*593dc095SDavid du Colombier 		/* Must not happen, becuse pdf_encode_glyph was passed in process_plain_text.*/
134*593dc095SDavid du Colombier 		ch = GS_NO_CHAR;
135*593dc095SDavid du Colombier 	    } else if (char_code_length != 1) {
136*593dc095SDavid du Colombier 		/* Must not happen with type 3 fonts.*/
137*593dc095SDavid du Colombier 		ch = GS_NO_CHAR;
138*593dc095SDavid du Colombier 	    } else
139*593dc095SDavid du Colombier 		ch = buf[0];
140*593dc095SDavid du Colombier 	} else {
141*593dc095SDavid du Colombier 	    ch = penum->text.data.bytes[penum->index];
142*593dc095SDavid du Colombier 	    glyph = font->procs.encode_char(font, ch, GLYPH_SPACE_NAME);
143*593dc095SDavid du Colombier 	    /*
144*593dc095SDavid du Colombier 	     * If glyph == GS_NO_GLYPH, we should replace it with
145*593dc095SDavid du Colombier 	     * a notdef glyph, but we don't know how to do with Type 3 fonts.
146*593dc095SDavid du Colombier 	     */
147*593dc095SDavid du Colombier 	}
148*593dc095SDavid du Colombier 	if (glyph != GS_NO_GLYPH && ch != GS_NO_CHAR) {
149*593dc095SDavid du Colombier 	    gs_show_enum *penum_s;
150*593dc095SDavid du Colombier 	    extern_st(st_gs_show_enum);
151*593dc095SDavid du Colombier 	    gs_fixed_rect clip_box;
152*593dc095SDavid du Colombier 	    double pw1[10];
153*593dc095SDavid du Colombier 	    int narg = (control == TEXT_SET_CHAR_WIDTH ? 2 :
154*593dc095SDavid du Colombier 			control == TEXT_SET_CACHE_DEVICE ? 6 : 10), i;
155*593dc095SDavid du Colombier 
156*593dc095SDavid du Colombier 	    if (penum->pte_default == NULL)
157*593dc095SDavid du Colombier 		return_error(gs_error_unregistered); /* Must not happen. */
158*593dc095SDavid du Colombier 	    /* Check to verify the structure type is really gs_show_enum */
159*593dc095SDavid du Colombier 	    if (gs_object_type(penum->pte_default->memory, penum->pte_default) != &st_gs_show_enum) {
160*593dc095SDavid du Colombier 		/* Must not happen with PS interpreter.
161*593dc095SDavid du Colombier 		   Other clients should conform. */
162*593dc095SDavid du Colombier 		return_error(gs_error_unregistered);
163*593dc095SDavid du Colombier 	    }
164*593dc095SDavid du Colombier 	    penum_s = (gs_show_enum *)penum->pte_default;
165*593dc095SDavid du Colombier 	    code = font->procs.glyph_name(font, glyph, &gnstr);
166*593dc095SDavid du Colombier 	    if (code < 0)
167*593dc095SDavid du Colombier 		return_error(gs_error_unregistered); /* Must not happen. */
168*593dc095SDavid du Colombier 	    /* BuildChar could change the scale before calling setcachedevice (Bug 687290).
169*593dc095SDavid du Colombier 	       We must scale the setcachedevice arguments because we assumed
170*593dc095SDavid du Colombier 	       identity scale before entering the charproc.
171*593dc095SDavid du Colombier 	       For now we only handle scaling matrices.
172*593dc095SDavid du Colombier 	    */
173*593dc095SDavid du Colombier 	    for (i = 0; i < narg; i += 2) {
174*593dc095SDavid du Colombier 		gs_point p;
175*593dc095SDavid du Colombier 
176*593dc095SDavid du Colombier 		gs_point_transform(pw[i], pw[i + 1], &ctm_only(penum_s->pgs), &p);
177*593dc095SDavid du Colombier 		pw1[i] = p.x;
178*593dc095SDavid du Colombier 		pw1[i + 1] = p.y;
179*593dc095SDavid du Colombier 	    }
180*593dc095SDavid du Colombier 	    if (control != TEXT_SET_CHAR_WIDTH) {
181*593dc095SDavid du Colombier 		clip_box.p.x = float2fixed(pw1[2]);
182*593dc095SDavid du Colombier 		clip_box.p.y = float2fixed(pw1[3]);
183*593dc095SDavid du Colombier 		clip_box.q.x = float2fixed(pw1[4]);
184*593dc095SDavid du Colombier 		clip_box.q.y = float2fixed(pw1[5]);
185*593dc095SDavid du Colombier 	    } else {
186*593dc095SDavid du Colombier 		/*
187*593dc095SDavid du Colombier 		 * We have no character bbox, but we need one to install the clipping
188*593dc095SDavid du Colombier 		 * to the graphic state of the PS interpreter. Since some fonts don't
189*593dc095SDavid du Colombier 		 * provide a proper FontBBox (Bug 687239 supplies a zero one),
190*593dc095SDavid du Colombier 		 * we set an "infinite" clipping here.
191*593dc095SDavid du Colombier 		 * We also detected that min_int, max_int don't work here with
192*593dc095SDavid du Colombier 		 * comparefiles/Bug687044.ps, therefore we divide them by 2.
193*593dc095SDavid du Colombier 		 */
194*593dc095SDavid du Colombier 		clip_box.p.x = clip_box.p.y = min_int / 2;
195*593dc095SDavid du Colombier 		clip_box.q.x = clip_box.q.y = max_int / 2;
196*593dc095SDavid du Colombier 	    }
197*593dc095SDavid du Colombier 	    code = gx_clip_to_rectangle(penum_s->pgs, &clip_box);
198*593dc095SDavid du Colombier 	    if (code < 0)
199*593dc095SDavid du Colombier 		return code;
200*593dc095SDavid du Colombier 	    code = pdf_set_charproc_attrs(pdev, pte->current_font,
201*593dc095SDavid du Colombier 			pw1, narg, control, ch, &gnstr);
202*593dc095SDavid du Colombier 	    if (code < 0)
203*593dc095SDavid du Colombier 		return code;
204*593dc095SDavid du Colombier 	    /* Prevent writing the clipping path to charproc.
205*593dc095SDavid du Colombier 	       See the comment above and bugs 687678, 688327.
206*593dc095SDavid du Colombier 	       Note that the clipping in the graphic state will be used while
207*593dc095SDavid du Colombier 	       fallbacks to default implementations of graphic objects.
208*593dc095SDavid du Colombier 	       Hopely such fallbacks are rare. */
209*593dc095SDavid du Colombier 	    pdev->clip_path_id = gx_get_clip_path_id(penum_s->pgs);
210*593dc095SDavid du Colombier 	    penum->charproc_accum = true;
211*593dc095SDavid du Colombier 	    return code;
212*593dc095SDavid du Colombier 	} else {
213*593dc095SDavid du Colombier 	    gs_matrix m;
214*593dc095SDavid du Colombier 	    pdf_resource_t *pres = pdev->accumulating_substream_resource;
215*593dc095SDavid du Colombier 
216*593dc095SDavid du Colombier 	    /* pdf_text_process started a charproc stream accumulation,
217*593dc095SDavid du Colombier 	       but now we re-decided to go with the default implementation.
218*593dc095SDavid du Colombier 	       Cancel the stream now.
219*593dc095SDavid du Colombier 	     */
220*593dc095SDavid du Colombier 	    code = pdf_exit_substream(pdev);
221*593dc095SDavid du Colombier 	    if (code < 0)
222*593dc095SDavid du Colombier 		return code;
223*593dc095SDavid du Colombier 	    code = pdf_cancel_resource(pdev, pres, resourceCharProc);
224*593dc095SDavid du Colombier 	    if (code < 0)
225*593dc095SDavid du Colombier 		return code;
226*593dc095SDavid du Colombier 	    pdf_forget_resource(pdev, pres, resourceCharProc);
227*593dc095SDavid du Colombier 	    /* pdf_text_process had set an identity CTM for the
228*593dc095SDavid du Colombier 	       charproc stream accumulation, but now we re-decided
229*593dc095SDavid du Colombier 	       to go with the default implementation.
230*593dc095SDavid du Colombier 	       Need to restore the correct CTM and add
231*593dc095SDavid du Colombier 	       changes, which the charproc possibly did. */
232*593dc095SDavid du Colombier 	    gs_matrix_multiply((gs_matrix *)&pdev->charproc_ctm, (gs_matrix *)&penum->pis->ctm, &m);
233*593dc095SDavid du Colombier 	    gs_matrix_fixed_from_matrix(&penum->pis->ctm, &m);
234*593dc095SDavid du Colombier 	}
235*593dc095SDavid du Colombier     }
236*593dc095SDavid du Colombier     if (penum->pte_default) {
237*593dc095SDavid du Colombier 	if (penum->pte_default->text.operation & TEXT_DO_CHARWIDTH /* See process_cmap_text.*/)
238*593dc095SDavid du Colombier 	    return gs_text_set_cache(penum->pte_default, pw, TEXT_SET_CHAR_WIDTH);
239*593dc095SDavid du Colombier 	else
240*593dc095SDavid du Colombier 	    return gs_text_set_cache(penum->pte_default, pw, control);
241*593dc095SDavid du Colombier     }
242*593dc095SDavid du Colombier     return_error(gs_error_unregistered); /* can't happen */
243*593dc095SDavid du Colombier }
244*593dc095SDavid du Colombier private int
pdf_text_retry(gs_text_enum_t * pte)245*593dc095SDavid du Colombier pdf_text_retry(gs_text_enum_t *pte)
246*593dc095SDavid du Colombier {
247*593dc095SDavid du Colombier     pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
248*593dc095SDavid du Colombier 
249*593dc095SDavid du Colombier     if (penum->pte_default)
250*593dc095SDavid du Colombier 	return gs_text_retry(penum->pte_default);
251*593dc095SDavid du Colombier     return_error(gs_error_rangecheck); /* can't happen */
252*593dc095SDavid du Colombier }
253*593dc095SDavid du Colombier private void
pdf_text_release(gs_text_enum_t * pte,client_name_t cname)254*593dc095SDavid du Colombier pdf_text_release(gs_text_enum_t *pte, client_name_t cname)
255*593dc095SDavid du Colombier {
256*593dc095SDavid du Colombier     pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
257*593dc095SDavid du Colombier 
258*593dc095SDavid du Colombier     if (penum->pte_default) {
259*593dc095SDavid du Colombier 	gs_text_release(penum->pte_default, cname);
260*593dc095SDavid du Colombier 	penum->pte_default = 0;
261*593dc095SDavid du Colombier     }
262*593dc095SDavid du Colombier     pdf_text_release_cgp(penum);
263*593dc095SDavid du Colombier     gx_default_text_release(pte, cname);
264*593dc095SDavid du Colombier }
265*593dc095SDavid du Colombier void
pdf_text_release_cgp(pdf_text_enum_t * penum)266*593dc095SDavid du Colombier pdf_text_release_cgp(pdf_text_enum_t *penum)
267*593dc095SDavid du Colombier {
268*593dc095SDavid du Colombier     if (penum->cgp) {
269*593dc095SDavid du Colombier 	gs_free_object(penum->memory, penum->cgp, "pdf_text_release");
270*593dc095SDavid du Colombier 	penum->cgp = 0;
271*593dc095SDavid du Colombier     }
272*593dc095SDavid du Colombier }
273*593dc095SDavid du Colombier 
274*593dc095SDavid du Colombier /* Begin processing text. */
275*593dc095SDavid du Colombier private text_enum_proc_process(pdf_text_process);
276*593dc095SDavid du Colombier private const gs_text_enum_procs_t pdf_text_procs = {
277*593dc095SDavid du Colombier     pdf_text_resync, pdf_text_process,
278*593dc095SDavid du Colombier     pdf_text_is_width_only, pdf_text_current_width,
279*593dc095SDavid du Colombier     pdf_text_set_cache, pdf_text_retry,
280*593dc095SDavid du Colombier     pdf_text_release
281*593dc095SDavid du Colombier };
282*593dc095SDavid du Colombier 
283*593dc095SDavid du Colombier private int
pdf_prepare_text_drawing(gx_device_pdf * const pdev,gs_text_enum_t * pte)284*593dc095SDavid du Colombier pdf_prepare_text_drawing(gx_device_pdf *const pdev, gs_text_enum_t *pte)
285*593dc095SDavid du Colombier {
286*593dc095SDavid du Colombier     gs_imager_state * pis = pte->pis;
287*593dc095SDavid du Colombier     const gx_device_color * pdcolor = pte->pdcolor;
288*593dc095SDavid du Colombier     const gx_clip_path * pcpath = pte->pcpath;
289*593dc095SDavid du Colombier     const gs_text_params_t *text = &pte->text;
290*593dc095SDavid du Colombier     bool new_clip = false; /* Quiet compiler. */
291*593dc095SDavid du Colombier     int code;
292*593dc095SDavid du Colombier 
293*593dc095SDavid du Colombier     if (!(text->operation & TEXT_DO_NONE) || pis->text_rendering_mode == 3) {
294*593dc095SDavid du Colombier 	new_clip = pdf_must_put_clip_path(pdev, pcpath);
295*593dc095SDavid du Colombier 	if (new_clip)
296*593dc095SDavid du Colombier 	    code = pdf_unclip(pdev);
297*593dc095SDavid du Colombier 	else if (pdev->context == PDF_IN_NONE)
298*593dc095SDavid du Colombier 	    code = pdf_open_page(pdev, PDF_IN_STREAM);
299*593dc095SDavid du Colombier 	else
300*593dc095SDavid du Colombier 	    code = 0;
301*593dc095SDavid du Colombier 	if (code < 0)
302*593dc095SDavid du Colombier 	    return code;
303*593dc095SDavid du Colombier 	code = pdf_prepare_fill(pdev, pis);
304*593dc095SDavid du Colombier 	if (code < 0)
305*593dc095SDavid du Colombier 	    return code;
306*593dc095SDavid du Colombier     }
307*593dc095SDavid du Colombier     if (text->operation & TEXT_DO_DRAW) {
308*593dc095SDavid du Colombier 	/*
309*593dc095SDavid du Colombier 	 * Set the clipping path and drawing color.  We set both the fill
310*593dc095SDavid du Colombier 	 * and stroke color, because we don't know whether the fonts will be
311*593dc095SDavid du Colombier 	 * filled or stroked, and we can't set a color while we are in text
312*593dc095SDavid du Colombier 	 * mode.  (This is a consequence of the implementation, not a
313*593dc095SDavid du Colombier 	 * limitation of PDF.)
314*593dc095SDavid du Colombier 	 */
315*593dc095SDavid du Colombier 
316*593dc095SDavid du Colombier 	if (new_clip) {
317*593dc095SDavid du Colombier 	    code = pdf_put_clip_path(pdev, pcpath);
318*593dc095SDavid du Colombier 	    if (code < 0)
319*593dc095SDavid du Colombier 		return code;
320*593dc095SDavid du Colombier 	}
321*593dc095SDavid du Colombier 
322*593dc095SDavid du Colombier 	if ((code =
323*593dc095SDavid du Colombier 	     pdf_set_drawing_color(pdev, pis, pdcolor, &pdev->saved_stroke_color,
324*593dc095SDavid du Colombier 				   &pdev->stroke_used_process_color,
325*593dc095SDavid du Colombier 				   &psdf_set_stroke_color_commands)) < 0 ||
326*593dc095SDavid du Colombier 	    (code =
327*593dc095SDavid du Colombier 	     pdf_set_drawing_color(pdev, pis, pdcolor, &pdev->saved_fill_color,
328*593dc095SDavid du Colombier 				   &pdev->fill_used_process_color,
329*593dc095SDavid du Colombier 				   &psdf_set_fill_color_commands)) < 0
330*593dc095SDavid du Colombier 	    )
331*593dc095SDavid du Colombier 	    return code;
332*593dc095SDavid du Colombier     }
333*593dc095SDavid du Colombier     return 0;
334*593dc095SDavid du Colombier }
335*593dc095SDavid du Colombier 
336*593dc095SDavid du Colombier int
gdev_pdf_text_begin(gx_device * dev,gs_imager_state * pis,const gs_text_params_t * text,gs_font * font,gx_path * path0,const gx_device_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gs_text_enum_t ** ppte)337*593dc095SDavid du Colombier gdev_pdf_text_begin(gx_device * dev, gs_imager_state * pis,
338*593dc095SDavid du Colombier 		    const gs_text_params_t *text, gs_font * font,
339*593dc095SDavid du Colombier 		    gx_path * path0, const gx_device_color * pdcolor,
340*593dc095SDavid du Colombier 		    const gx_clip_path * pcpath,
341*593dc095SDavid du Colombier 		    gs_memory_t * mem, gs_text_enum_t ** ppte)
342*593dc095SDavid du Colombier {
343*593dc095SDavid du Colombier     gx_device_pdf *const pdev = (gx_device_pdf *)dev;
344*593dc095SDavid du Colombier     gx_path *path = path0;
345*593dc095SDavid du Colombier     pdf_text_enum_t *penum;
346*593dc095SDavid du Colombier     gs_fixed_point cpt;
347*593dc095SDavid du Colombier     int code;
348*593dc095SDavid du Colombier 
349*593dc095SDavid du Colombier     /* Track the dominant text rotation. */
350*593dc095SDavid du Colombier     {
351*593dc095SDavid du Colombier 	gs_matrix tmat;
352*593dc095SDavid du Colombier 	int i;
353*593dc095SDavid du Colombier 
354*593dc095SDavid du Colombier 	gs_matrix_multiply(&font->FontMatrix, &ctm_only(pis), &tmat);
355*593dc095SDavid du Colombier 	if (is_xxyy(&tmat))
356*593dc095SDavid du Colombier 	    i = (tmat.xx >= 0 ? 0 : 2);
357*593dc095SDavid du Colombier 	else if (is_xyyx(&tmat))
358*593dc095SDavid du Colombier 	    i = (tmat.xy >= 0 ? 1 : 3);
359*593dc095SDavid du Colombier 	else
360*593dc095SDavid du Colombier 	    i = 4;
361*593dc095SDavid du Colombier 	pdf_current_page(pdev)->text_rotation.counts[i] += text->size;
362*593dc095SDavid du Colombier     }
363*593dc095SDavid du Colombier 
364*593dc095SDavid du Colombier     if (font->FontType == ft_user_defined &&
365*593dc095SDavid du Colombier 	(text->operation & TEXT_DO_NONE) && (text->operation & TEXT_RETURN_WIDTH)) {
366*593dc095SDavid du Colombier 	/* This is stringwidth, see gx_default_text_begin.
367*593dc095SDavid du Colombier 	 * We need to prevent writing characters to PS cache,
368*593dc095SDavid du Colombier 	 * otherwise the font converts to bitmaps.
369*593dc095SDavid du Colombier 	 * So pass through even with stringwidth.
370*593dc095SDavid du Colombier 	 */
371*593dc095SDavid du Colombier 	code = gx_hld_stringwidth_begin(pis, &path);
372*593dc095SDavid du Colombier 	if (code < 0)
373*593dc095SDavid du Colombier 	    return code;
374*593dc095SDavid du Colombier     } else if ((!(text->operation & TEXT_DO_DRAW) && pis->text_rendering_mode != 3)
375*593dc095SDavid du Colombier 		|| path == 0 || gx_path_current_point(path, &cpt) < 0
376*593dc095SDavid du Colombier 	    )
377*593dc095SDavid du Colombier 	return gx_default_text_begin(dev, pis, text, font, path, pdcolor,
378*593dc095SDavid du Colombier 					 pcpath, mem, ppte);
379*593dc095SDavid du Colombier 
380*593dc095SDavid du Colombier     /* Allocate and initialize the enumerator. */
381*593dc095SDavid du Colombier 
382*593dc095SDavid du Colombier     rc_alloc_struct_1(penum, pdf_text_enum_t, &st_pdf_text_enum, mem,
383*593dc095SDavid du Colombier 		      return_error(gs_error_VMerror), "gdev_pdf_text_begin");
384*593dc095SDavid du Colombier     penum->rc.free = rc_free_text_enum;
385*593dc095SDavid du Colombier     penum->pte_default = 0;
386*593dc095SDavid du Colombier     penum->charproc_accum = false;
387*593dc095SDavid du Colombier     penum->cdevproc_callout = false;
388*593dc095SDavid du Colombier     penum->returned.total_width.x = penum->returned.total_width.y = 0;
389*593dc095SDavid du Colombier     penum->cgp = NULL;
390*593dc095SDavid du Colombier     code = gs_text_enum_init((gs_text_enum_t *)penum, &pdf_text_procs,
391*593dc095SDavid du Colombier 			     dev, pis, text, font, path, pdcolor, pcpath, mem);
392*593dc095SDavid du Colombier     if (code < 0) {
393*593dc095SDavid du Colombier 	gs_free_object(mem, penum, "gdev_pdf_text_begin");
394*593dc095SDavid du Colombier 	return code;
395*593dc095SDavid du Colombier     }
396*593dc095SDavid du Colombier     if (pdev->font3 != 0) {
397*593dc095SDavid du Colombier 	/* A text operation happens while accumulating a charproc.
398*593dc095SDavid du Colombier 	   This is a case when source document uses a Type 3 font,
399*593dc095SDavid du Colombier 	   which's charproc uses another font.
400*593dc095SDavid du Colombier 	   Since the text operation is handled by the device,
401*593dc095SDavid du Colombier 	   the font isn't converting to a raster (i.e. to a bitmap font).
402*593dc095SDavid du Colombier 	   Disable the grid fitting for the convertion to get a proper outlines,
403*593dc095SDavid du Colombier 	   because the viewer resolution is not known during the accumulation.
404*593dc095SDavid du Colombier 	   Note we set identity CTM in pdf_text_set_cache for the accumilation,
405*593dc095SDavid du Colombier 	   and therefore the font may look too small while the source charproc
406*593dc095SDavid du Colombier 	   interpretation. The document tpc2.ps of the bug 687087 is an example.
407*593dc095SDavid du Colombier 	*/
408*593dc095SDavid du Colombier 	penum->device_disabled_grid_fitting = true;
409*593dc095SDavid du Colombier     }
410*593dc095SDavid du Colombier 
411*593dc095SDavid du Colombier     *ppte = (gs_text_enum_t *)penum;
412*593dc095SDavid du Colombier 
413*593dc095SDavid du Colombier     return 0;
414*593dc095SDavid du Colombier }
415*593dc095SDavid du Colombier 
416*593dc095SDavid du Colombier /* ================ Font cache element ================ */
417*593dc095SDavid du Colombier 
418*593dc095SDavid du Colombier /* GC descriptor */
419*593dc095SDavid du Colombier private_st_pdf_font_cache_elem();
420*593dc095SDavid du Colombier 
421*593dc095SDavid du Colombier /*
422*593dc095SDavid du Colombier  * Compute id for a font cache element.
423*593dc095SDavid du Colombier  */
424*593dc095SDavid du Colombier private ulong
pdf_font_cache_elem_id(gs_font * font)425*593dc095SDavid du Colombier pdf_font_cache_elem_id(gs_font *font)
426*593dc095SDavid du Colombier {
427*593dc095SDavid du Colombier #if 0
428*593dc095SDavid du Colombier     /*
429*593dc095SDavid du Colombier      *	For compatibility with Ghostscript rasterizer's
430*593dc095SDavid du Colombier      *	cache logic we use UniqueID to identify fonts.
431*593dc095SDavid du Colombier      *  Note that with buggy documents, which don't
432*593dc095SDavid du Colombier      *	undefine UniqueID redefining a font,
433*593dc095SDavid du Colombier      *	Ghostscript PS interpreter can occasionaly
434*593dc095SDavid du Colombier      *	replace cache elements on insufficient cache size,
435*593dc095SDavid du Colombier      *	taking glyphs from random fonts with random metrics,
436*593dc095SDavid du Colombier      *	therefore the compatibility isn't complete.
437*593dc095SDavid du Colombier      */
438*593dc095SDavid du Colombier     /*
439*593dc095SDavid du Colombier      *	This branch is incompatible with pdf_notify_remove_font.
440*593dc095SDavid du Colombier      */
441*593dc095SDavid du Colombier     if (font->FontType == ft_composite || font->PaintType != 0 ||
442*593dc095SDavid du Colombier 	!uid_is_valid(&(((gs_font_base *)font)->UID)))
443*593dc095SDavid du Colombier 	return font->id;
444*593dc095SDavid du Colombier     else
445*593dc095SDavid du Colombier 	return ((gs_font_base *)font)->UID.id;
446*593dc095SDavid du Colombier #else
447*593dc095SDavid du Colombier     return font->id;
448*593dc095SDavid du Colombier #endif
449*593dc095SDavid du Colombier }
450*593dc095SDavid du Colombier 
451*593dc095SDavid du Colombier private pdf_font_cache_elem_t **
pdf_locate_font_cache_elem(gx_device_pdf * pdev,gs_font * font)452*593dc095SDavid du Colombier pdf_locate_font_cache_elem(gx_device_pdf *pdev, gs_font *font)
453*593dc095SDavid du Colombier {
454*593dc095SDavid du Colombier     pdf_font_cache_elem_t **e = &pdev->font_cache;
455*593dc095SDavid du Colombier     long id = pdf_font_cache_elem_id(font);
456*593dc095SDavid du Colombier 
457*593dc095SDavid du Colombier     for (; *e != 0; e = &(*e)->next)
458*593dc095SDavid du Colombier 	if ((*e)->font_id == id) {
459*593dc095SDavid du Colombier 	    return e;
460*593dc095SDavid du Colombier 	}
461*593dc095SDavid du Colombier     return 0;
462*593dc095SDavid du Colombier }
463*593dc095SDavid du Colombier 
464*593dc095SDavid du Colombier private void
pdf_remove_font_cache_elem(pdf_font_cache_elem_t * e0)465*593dc095SDavid du Colombier pdf_remove_font_cache_elem(pdf_font_cache_elem_t *e0)
466*593dc095SDavid du Colombier {
467*593dc095SDavid du Colombier     gx_device_pdf *pdev = e0->pdev;
468*593dc095SDavid du Colombier     pdf_font_cache_elem_t **e = &pdev->font_cache;
469*593dc095SDavid du Colombier 
470*593dc095SDavid du Colombier     for (; *e != 0; e = &(*e)->next)
471*593dc095SDavid du Colombier 	if (*e == e0) {
472*593dc095SDavid du Colombier 	    *e = e0->next;
473*593dc095SDavid du Colombier 	    gs_free_object(pdev->pdf_memory, e0->glyph_usage,
474*593dc095SDavid du Colombier 				"pdf_remove_font_cache_elem");
475*593dc095SDavid du Colombier 	    gs_free_object(pdev->pdf_memory, e0->real_widths,
476*593dc095SDavid du Colombier 				"pdf_remove_font_cache_elem");
477*593dc095SDavid du Colombier 	    e0->glyph_usage = 0;
478*593dc095SDavid du Colombier 	    e0->real_widths = 0;
479*593dc095SDavid du Colombier 	    gs_free_object(pdev->pdf_memory, e0,
480*593dc095SDavid du Colombier 				"pdf_remove_font_cache_elem");
481*593dc095SDavid du Colombier 	    return;
482*593dc095SDavid du Colombier 	}
483*593dc095SDavid du Colombier }
484*593dc095SDavid du Colombier 
485*593dc095SDavid du Colombier private void
font_cache_elem_array_sizes(gx_device_pdf * pdev,gs_font * font,int * num_widths,int * num_chars)486*593dc095SDavid du Colombier font_cache_elem_array_sizes(gx_device_pdf *pdev, gs_font *font,
487*593dc095SDavid du Colombier 			    int *num_widths, int *num_chars)
488*593dc095SDavid du Colombier {
489*593dc095SDavid du Colombier     switch (font->FontType) {
490*593dc095SDavid du Colombier     case ft_composite:
491*593dc095SDavid du Colombier 	*num_widths = 0; /* Unused for Type 0 */
492*593dc095SDavid du Colombier 	*num_chars = 65536; /* No chance to determine, use max. */
493*593dc095SDavid du Colombier 	break;
494*593dc095SDavid du Colombier     case ft_encrypted:
495*593dc095SDavid du Colombier     case ft_encrypted2:
496*593dc095SDavid du Colombier     case ft_user_defined:
497*593dc095SDavid du Colombier     case ft_disk_based:
498*593dc095SDavid du Colombier     case ft_Chameleon:
499*593dc095SDavid du Colombier     case ft_TrueType:
500*593dc095SDavid du Colombier 	*num_widths = *num_chars = 256; /* Assuming access to glyph_usage by character codes */
501*593dc095SDavid du Colombier 	break;
502*593dc095SDavid du Colombier     case ft_CID_encrypted:
503*593dc095SDavid du Colombier 	*num_widths = *num_chars = ((gs_font_cid0 *)font)->cidata.common.CIDCount;
504*593dc095SDavid du Colombier 	break;
505*593dc095SDavid du Colombier     case ft_CID_TrueType:
506*593dc095SDavid du Colombier 	*num_widths = *num_chars = ((gs_font_cid2 *)font)->cidata.common.CIDCount;
507*593dc095SDavid du Colombier 	break;
508*593dc095SDavid du Colombier     default:
509*593dc095SDavid du Colombier 	*num_widths = *num_chars = 65536; /* No chance to determine, use max. */
510*593dc095SDavid du Colombier     }
511*593dc095SDavid du Colombier }
512*593dc095SDavid du Colombier 
513*593dc095SDavid du Colombier private int
alloc_font_cache_elem_arrays(gx_device_pdf * pdev,pdf_font_cache_elem_t * e,gs_font * font)514*593dc095SDavid du Colombier alloc_font_cache_elem_arrays(gx_device_pdf *pdev, pdf_font_cache_elem_t *e,
515*593dc095SDavid du Colombier 			     gs_font *font)
516*593dc095SDavid du Colombier {
517*593dc095SDavid du Colombier     int num_widths, num_chars, len;
518*593dc095SDavid du Colombier 
519*593dc095SDavid du Colombier     font_cache_elem_array_sizes(pdev, font, &num_widths, &num_chars);
520*593dc095SDavid du Colombier     len = (num_chars + 7) / 8;
521*593dc095SDavid du Colombier     e->glyph_usage = gs_alloc_bytes(pdev->pdf_memory,
522*593dc095SDavid du Colombier 			len, "alloc_font_cache_elem_arrays");
523*593dc095SDavid du Colombier 
524*593dc095SDavid du Colombier     e->real_widths = (num_widths > 0 ? (double *)gs_alloc_bytes(pdev->pdf_memory,
525*593dc095SDavid du Colombier 			num_widths * sizeof(*e->real_widths) *
526*593dc095SDavid du Colombier 			    (font->FontType == ft_user_defined ? 2 : 1),
527*593dc095SDavid du Colombier 			"alloc_font_cache_elem_arrays") : NULL);
528*593dc095SDavid du Colombier     if (e->glyph_usage == NULL || (num_widths !=0 && e->real_widths == NULL)) {
529*593dc095SDavid du Colombier 	gs_free_object(pdev->pdf_memory, e->glyph_usage,
530*593dc095SDavid du Colombier 			    "pdf_attach_font_resource");
531*593dc095SDavid du Colombier 	gs_free_object(pdev->pdf_memory, e->real_widths,
532*593dc095SDavid du Colombier 			    "alloc_font_cache_elem_arrays");
533*593dc095SDavid du Colombier 	return_error(gs_error_VMerror);
534*593dc095SDavid du Colombier     }
535*593dc095SDavid du Colombier     e->num_chars = num_chars;
536*593dc095SDavid du Colombier     e->num_widths = num_widths;
537*593dc095SDavid du Colombier     memset(e->glyph_usage, 0, len);
538*593dc095SDavid du Colombier     memset(e->real_widths, 0, num_widths * sizeof(*e->real_widths));
539*593dc095SDavid du Colombier     return 0;
540*593dc095SDavid du Colombier }
541*593dc095SDavid du Colombier 
542*593dc095SDavid du Colombier int
pdf_free_font_cache(gx_device_pdf * pdev)543*593dc095SDavid du Colombier pdf_free_font_cache(gx_device_pdf *pdev)
544*593dc095SDavid du Colombier {
545*593dc095SDavid du Colombier     /* fixme : release elements. */
546*593dc095SDavid du Colombier     pdev->font_cache = NULL;
547*593dc095SDavid du Colombier     return 0;
548*593dc095SDavid du Colombier }
549*593dc095SDavid du Colombier 
550*593dc095SDavid du Colombier 
551*593dc095SDavid du Colombier /*
552*593dc095SDavid du Colombier  * Retrive font resource attached to a font,
553*593dc095SDavid du Colombier  * allocating glyph_usage and real_widths on request.
554*593dc095SDavid du Colombier  */
555*593dc095SDavid du Colombier int
pdf_attached_font_resource(gx_device_pdf * pdev,gs_font * font,pdf_font_resource_t ** pdfont,byte ** glyph_usage,double ** real_widths,int * num_chars,int * num_widths)556*593dc095SDavid du Colombier pdf_attached_font_resource(gx_device_pdf *pdev, gs_font *font,
557*593dc095SDavid du Colombier 			    pdf_font_resource_t **pdfont, byte **glyph_usage,
558*593dc095SDavid du Colombier 			    double **real_widths, int *num_chars, int *num_widths)
559*593dc095SDavid du Colombier {
560*593dc095SDavid du Colombier     pdf_font_cache_elem_t **e = pdf_locate_font_cache_elem(pdev, font);
561*593dc095SDavid du Colombier 
562*593dc095SDavid du Colombier     if (e != NULL && (((*e)->glyph_usage == NULL && glyph_usage !=NULL) ||
563*593dc095SDavid du Colombier 		      ((*e)->real_widths == NULL && real_widths !=NULL))) {
564*593dc095SDavid du Colombier 	int code = alloc_font_cache_elem_arrays(pdev, *e, font);
565*593dc095SDavid du Colombier 
566*593dc095SDavid du Colombier 	if (code < 0)
567*593dc095SDavid du Colombier 	    return code;
568*593dc095SDavid du Colombier     }
569*593dc095SDavid du Colombier     *pdfont = (e == NULL ? NULL : (*e)->pdfont);
570*593dc095SDavid du Colombier     if (glyph_usage != NULL)
571*593dc095SDavid du Colombier 	*glyph_usage = (e == NULL ? NULL : (*e)->glyph_usage);
572*593dc095SDavid du Colombier     if (real_widths != NULL)
573*593dc095SDavid du Colombier 	*real_widths = (e == NULL ? NULL : (*e)->real_widths);
574*593dc095SDavid du Colombier     if (num_chars != NULL)
575*593dc095SDavid du Colombier 	*num_chars = (e == NULL ? 0 : (*e)->num_chars);
576*593dc095SDavid du Colombier     if (num_widths != NULL)
577*593dc095SDavid du Colombier 	*num_widths = (e == NULL ? 0 : (*e)->num_widths);
578*593dc095SDavid du Colombier     return 0;
579*593dc095SDavid du Colombier }
580*593dc095SDavid du Colombier 
581*593dc095SDavid du Colombier private int
pdf_notify_remove_font(void * proc_data,void * event_data)582*593dc095SDavid du Colombier pdf_notify_remove_font(void *proc_data, void *event_data)
583*593dc095SDavid du Colombier {   /* gs_font_finalize passes event_data == NULL, so check it here. */
584*593dc095SDavid du Colombier     if (event_data == NULL)
585*593dc095SDavid du Colombier 	pdf_remove_font_cache_elem((pdf_font_cache_elem_t *)proc_data);
586*593dc095SDavid du Colombier     return 0;
587*593dc095SDavid du Colombier }
588*593dc095SDavid du Colombier 
589*593dc095SDavid du Colombier /*
590*593dc095SDavid du Colombier  * Attach font resource to a font.
591*593dc095SDavid du Colombier  */
592*593dc095SDavid du Colombier int
pdf_attach_font_resource(gx_device_pdf * pdev,gs_font * font,pdf_font_resource_t * pdfont)593*593dc095SDavid du Colombier pdf_attach_font_resource(gx_device_pdf *pdev, gs_font *font,
594*593dc095SDavid du Colombier 			 pdf_font_resource_t *pdfont)
595*593dc095SDavid du Colombier {
596*593dc095SDavid du Colombier     int num_chars, num_widths, len;
597*593dc095SDavid du Colombier     pdf_font_cache_elem_t *e, **pe = pdf_locate_font_cache_elem(pdev, font);
598*593dc095SDavid du Colombier 
599*593dc095SDavid du Colombier     if (pdfont->FontType != font->FontType)
600*593dc095SDavid du Colombier 	return_error(gs_error_unregistered); /* Must not happen. */
601*593dc095SDavid du Colombier     font_cache_elem_array_sizes(pdev, font, &num_widths, &num_chars);
602*593dc095SDavid du Colombier     len = (num_chars + 7) / 8;
603*593dc095SDavid du Colombier     if (pe != NULL) {
604*593dc095SDavid du Colombier 	e = *pe;
605*593dc095SDavid du Colombier 	if (e->pdfont == pdfont)
606*593dc095SDavid du Colombier 	    return 0;
607*593dc095SDavid du Colombier 	e->pdfont = pdfont;
608*593dc095SDavid du Colombier 	/* Reset glyph cache because e->pdfont had changed. */
609*593dc095SDavid du Colombier 	memset(e->glyph_usage, 0, len);
610*593dc095SDavid du Colombier 	memset(e->real_widths, 0, num_widths * sizeof(*e->real_widths));
611*593dc095SDavid du Colombier     } else {
612*593dc095SDavid du Colombier 	int code;
613*593dc095SDavid du Colombier 	e = (pdf_font_cache_elem_t *)gs_alloc_struct(pdev->pdf_memory,
614*593dc095SDavid du Colombier 		pdf_font_cache_elem_t, &st_pdf_font_cache_elem,
615*593dc095SDavid du Colombier 			    "pdf_attach_font_resource");
616*593dc095SDavid du Colombier 	if (e == NULL)
617*593dc095SDavid du Colombier 	    return_error(gs_error_VMerror);
618*593dc095SDavid du Colombier 	e->pdfont = pdfont;
619*593dc095SDavid du Colombier 	e->font_id = pdf_font_cache_elem_id(font);
620*593dc095SDavid du Colombier 	e->num_chars = 0;
621*593dc095SDavid du Colombier 	e->glyph_usage = NULL;
622*593dc095SDavid du Colombier 	e->real_widths = NULL;
623*593dc095SDavid du Colombier 	e->pdev = pdev;
624*593dc095SDavid du Colombier 	e->next = pdev->font_cache;
625*593dc095SDavid du Colombier 	pdev->font_cache = e;
626*593dc095SDavid du Colombier 	code = gs_notify_register(&font->notify_list, pdf_notify_remove_font, e);
627*593dc095SDavid du Colombier 	if (code < 0)
628*593dc095SDavid du Colombier 	    return code;
629*593dc095SDavid du Colombier     }
630*593dc095SDavid du Colombier     return 0;
631*593dc095SDavid du Colombier }
632*593dc095SDavid du Colombier 
633*593dc095SDavid du Colombier /* ================ Process text ================ */
634*593dc095SDavid du Colombier 
635*593dc095SDavid du Colombier /* ---------------- Internal utilities ---------------- */
636*593dc095SDavid du Colombier 
637*593dc095SDavid du Colombier /*
638*593dc095SDavid du Colombier  * Compute and return the orig_matrix of a font.
639*593dc095SDavid du Colombier  */
640*593dc095SDavid du Colombier int
pdf_font_orig_matrix(const gs_font * font,gs_matrix * pmat)641*593dc095SDavid du Colombier pdf_font_orig_matrix(const gs_font *font, gs_matrix *pmat)
642*593dc095SDavid du Colombier {
643*593dc095SDavid du Colombier     switch (font->FontType) {
644*593dc095SDavid du Colombier     case ft_composite:		/* subfonts have their own FontMatrix */
645*593dc095SDavid du Colombier     case ft_TrueType:
646*593dc095SDavid du Colombier     case ft_CID_TrueType:
647*593dc095SDavid du Colombier 	/* The TrueType FontMatrix is 1 unit per em, which is what we want. */
648*593dc095SDavid du Colombier 	gs_make_identity(pmat);
649*593dc095SDavid du Colombier 	return 0;
650*593dc095SDavid du Colombier     case ft_encrypted:
651*593dc095SDavid du Colombier     case ft_encrypted2:
652*593dc095SDavid du Colombier     case ft_CID_encrypted:
653*593dc095SDavid du Colombier     case ft_user_defined:
654*593dc095SDavid du Colombier 	/*
655*593dc095SDavid du Colombier          * Type 1 fonts are supposed to use a standard FontMatrix of
656*593dc095SDavid du Colombier          * [0.001 0 0 0.001 0 0], with a 1000-unit cell.  However,
657*593dc095SDavid du Colombier          * Windows NT 4.0 creates Type 1 fonts, apparently derived from
658*593dc095SDavid du Colombier          * TrueType fonts, that use a 2048-unit cell and corresponding
659*593dc095SDavid du Colombier          * FontMatrix.  Also, some PS programs perform font scaling by
660*593dc095SDavid du Colombier          * replacing FontMatrix like this :
661*593dc095SDavid du Colombier          *
662*593dc095SDavid du Colombier          *   /f12 /Times-Roman findfont
663*593dc095SDavid du Colombier          *   copyfont	  % (remove FID)
664*593dc095SDavid du Colombier          *   dup /FontMatrix [0.012 0 0 0.012 0 0] put
665*593dc095SDavid du Colombier          *   definefont
666*593dc095SDavid du Colombier          *   /f12 1 selectfont
667*593dc095SDavid du Colombier          *
668*593dc095SDavid du Colombier          * Such fonts are their own "base font", but the orig_matrix
669*593dc095SDavid du Colombier          * must still be set to 0.001, not 0.012 .
670*593dc095SDavid du Colombier          *
671*593dc095SDavid du Colombier          * The old code used a heuristic to detect and correct for this here.
672*593dc095SDavid du Colombier 	 * Unfortunately it doesn't work properly when it meets a font
673*593dc095SDavid du Colombier 	 * with FontMatrix like this :
674*593dc095SDavid du Colombier 	 *
675*593dc095SDavid du Colombier 	 *   /FontMatrix [1 2288 div 0 0 1 2288 div 0 0 ] def
676*593dc095SDavid du Colombier 	 *
677*593dc095SDavid du Colombier 	 * (the bug 686970). Also comparefiles\455690.pdf appears to
678*593dc095SDavid du Colombier 	 * have similar problem. Therefore we added a support to lib/gs_fonts.ps,
679*593dc095SDavid du Colombier 	 * src/zbfont.c, src/gsfont.c that provides an acces to the original
680*593dc095SDavid du Colombier 	 * font via a special key .OrigFont added to the font dictionary while definefont.
681*593dc095SDavid du Colombier 	 * Now we work through this access with PS interpreter,
682*593dc095SDavid du Colombier 	 * but keep the old heuristic for other clients.
683*593dc095SDavid du Colombier 	 */
684*593dc095SDavid du Colombier 	{
685*593dc095SDavid du Colombier 	    const gs_font *base_font = font;
686*593dc095SDavid du Colombier 
687*593dc095SDavid du Colombier 	    while (base_font->base != base_font)
688*593dc095SDavid du Colombier 		base_font = base_font->base;
689*593dc095SDavid du Colombier 	    if (font->FontType == ft_user_defined)
690*593dc095SDavid du Colombier 		*pmat = base_font->FontMatrix;
691*593dc095SDavid du Colombier 	    else if (base_font->orig_FontMatrix.xx != 0 || base_font->orig_FontMatrix.xy != 0 ||
692*593dc095SDavid du Colombier 	        base_font->orig_FontMatrix.yx != 0 || base_font->orig_FontMatrix.yy != 0)
693*593dc095SDavid du Colombier 		*pmat = base_font->orig_FontMatrix;
694*593dc095SDavid du Colombier 	    else {
695*593dc095SDavid du Colombier 		/*  Must not happen with PS interpreter.
696*593dc095SDavid du Colombier 		    Provide a hewuristic for other clients.
697*593dc095SDavid du Colombier 		*/
698*593dc095SDavid du Colombier 		if (base_font->FontMatrix.xx == 1.0/2048 &&
699*593dc095SDavid du Colombier 		    base_font->FontMatrix.xy == 0 &&
700*593dc095SDavid du Colombier 		    base_font->FontMatrix.yx == 0 &&
701*593dc095SDavid du Colombier 		    any_abs(base_font->FontMatrix.yy) == 1.0/2048
702*593dc095SDavid du Colombier 		    )
703*593dc095SDavid du Colombier 		    *pmat = base_font->FontMatrix;
704*593dc095SDavid du Colombier 		else
705*593dc095SDavid du Colombier 		    gs_make_scaling(0.001, 0.001, pmat);
706*593dc095SDavid du Colombier 	    }
707*593dc095SDavid du Colombier 	}
708*593dc095SDavid du Colombier 	return 0;
709*593dc095SDavid du Colombier     default:
710*593dc095SDavid du Colombier 	return_error(gs_error_rangecheck);
711*593dc095SDavid du Colombier     }
712*593dc095SDavid du Colombier }
713*593dc095SDavid du Colombier 
714*593dc095SDavid du Colombier int
font_orig_scale(const gs_font * font,double * sx)715*593dc095SDavid du Colombier font_orig_scale(const gs_font *font, double *sx)
716*593dc095SDavid du Colombier {
717*593dc095SDavid du Colombier     gs_matrix mat;
718*593dc095SDavid du Colombier     int code = pdf_font_orig_matrix(font, &mat);
719*593dc095SDavid du Colombier 
720*593dc095SDavid du Colombier     if (code < 0)
721*593dc095SDavid du Colombier 	return code;
722*593dc095SDavid du Colombier     *sx = mat.xx;
723*593dc095SDavid du Colombier     return 0;
724*593dc095SDavid du Colombier }
725*593dc095SDavid du Colombier 
726*593dc095SDavid du Colombier /*
727*593dc095SDavid du Colombier  * Check the Encoding compatibility
728*593dc095SDavid du Colombier  */
729*593dc095SDavid du Colombier bool
pdf_check_encoding_compatibility(const pdf_font_resource_t * pdfont,const pdf_char_glyph_pair_t * pairs,int num_chars)730*593dc095SDavid du Colombier pdf_check_encoding_compatibility(const pdf_font_resource_t *pdfont,
731*593dc095SDavid du Colombier 	    const pdf_char_glyph_pair_t *pairs, int num_chars)
732*593dc095SDavid du Colombier {
733*593dc095SDavid du Colombier     int i;
734*593dc095SDavid du Colombier 
735*593dc095SDavid du Colombier     for (i = 0; i < num_chars; ++i) {
736*593dc095SDavid du Colombier 	gs_char ch = pairs[i].chr;
737*593dc095SDavid du Colombier 	pdf_encoding_element_t *pet = &pdfont->u.simple.Encoding[ch];
738*593dc095SDavid du Colombier 
739*593dc095SDavid du Colombier 	if (pairs[i].glyph == pet->glyph)
740*593dc095SDavid du Colombier 	    continue;
741*593dc095SDavid du Colombier 	if (pet->glyph != GS_NO_GLYPH) /* encoding conflict */
742*593dc095SDavid du Colombier 	    return false;
743*593dc095SDavid du Colombier     }
744*593dc095SDavid du Colombier     return true;
745*593dc095SDavid du Colombier }
746*593dc095SDavid du Colombier 
747*593dc095SDavid du Colombier /*
748*593dc095SDavid du Colombier  * Check font resource for encoding compatibility.
749*593dc095SDavid du Colombier  */
750*593dc095SDavid du Colombier private bool
pdf_is_compatible_encoding(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,gs_font * font,const pdf_char_glyph_pair_t * pairs,int num_chars)751*593dc095SDavid du Colombier pdf_is_compatible_encoding(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
752*593dc095SDavid du Colombier 			   gs_font *font, const pdf_char_glyph_pair_t *pairs, int num_chars)
753*593dc095SDavid du Colombier {
754*593dc095SDavid du Colombier     /*
755*593dc095SDavid du Colombier      * This crude version of the code ignores
756*593dc095SDavid du Colombier      * the possibility of re-encoding characters.
757*593dc095SDavid du Colombier      */
758*593dc095SDavid du Colombier     switch (pdfont->FontType) {
759*593dc095SDavid du Colombier     case ft_composite:
760*593dc095SDavid du Colombier 	{   /*
761*593dc095SDavid du Colombier 	     * We assume that source document don't redefine CMap
762*593dc095SDavid du Colombier 	     * resources and that incremental CMaps do not exist.
763*593dc095SDavid du Colombier 	     * Therefore we don't maintain stable CMap copies,
764*593dc095SDavid du Colombier 	     * but just compare CMap names for equality.
765*593dc095SDavid du Colombier 	     * A better implementation should compare the chars->glyphs
766*593dc095SDavid du Colombier 	     * translation against the stable copy of CMap,
767*593dc095SDavid du Colombier 	     * which to be handled with PDF CMap resource.
768*593dc095SDavid du Colombier 	     */
769*593dc095SDavid du Colombier 	    gs_font_type0 *pfont = (gs_font_type0 *)font;
770*593dc095SDavid du Colombier 
771*593dc095SDavid du Colombier 	    if (pfont->data.FMapType == fmap_CMap) {
772*593dc095SDavid du Colombier 		const gs_cmap_t *pcmap = pfont->data.CMap;
773*593dc095SDavid du Colombier 		const gs_const_string *s0 = &pdfont->u.type0.CMapName;
774*593dc095SDavid du Colombier 		const gs_const_string *s1 = &pcmap->CMapName;
775*593dc095SDavid du Colombier 
776*593dc095SDavid du Colombier 		return (s0->size == s1->size &&
777*593dc095SDavid du Colombier 			!memcmp(s0->data, s1->data, s0->size));
778*593dc095SDavid du Colombier 	    }
779*593dc095SDavid du Colombier 	}
780*593dc095SDavid du Colombier 	return false;
781*593dc095SDavid du Colombier     case ft_user_defined:
782*593dc095SDavid du Colombier 	if (pdfont->u.simple.Encoding == NULL)
783*593dc095SDavid du Colombier 	    return false; /* Not sure. Happens with 020-01.ps . */
784*593dc095SDavid du Colombier 	/* fall through */
785*593dc095SDavid du Colombier     case ft_encrypted:
786*593dc095SDavid du Colombier     case ft_encrypted2:
787*593dc095SDavid du Colombier     case ft_TrueType:
788*593dc095SDavid du Colombier 	return pdf_check_encoding_compatibility(pdfont, pairs, num_chars);
789*593dc095SDavid du Colombier     case ft_CID_encrypted:
790*593dc095SDavid du Colombier     case ft_CID_TrueType:
791*593dc095SDavid du Colombier 	{
792*593dc095SDavid du Colombier 	    gs_font *font1 = (gs_font *)pdf_font_resource_font(pdfont, false);
793*593dc095SDavid du Colombier 
794*593dc095SDavid du Colombier 	    return gs_is_CIDSystemInfo_compatible(
795*593dc095SDavid du Colombier 				gs_font_cid_system_info(font),
796*593dc095SDavid du Colombier 				gs_font_cid_system_info(font1));
797*593dc095SDavid du Colombier 	}
798*593dc095SDavid du Colombier     default:
799*593dc095SDavid du Colombier 	return false;
800*593dc095SDavid du Colombier     }
801*593dc095SDavid du Colombier }
802*593dc095SDavid du Colombier 
803*593dc095SDavid du Colombier /*
804*593dc095SDavid du Colombier  * Find a font resource compatible with a given font.
805*593dc095SDavid du Colombier  */
806*593dc095SDavid du Colombier private int
pdf_find_font_resource(gx_device_pdf * pdev,gs_font * font,pdf_resource_type_t type,pdf_font_resource_t ** ppdfont,pdf_char_glyph_pairs_t * cgp)807*593dc095SDavid du Colombier pdf_find_font_resource(gx_device_pdf *pdev, gs_font *font,
808*593dc095SDavid du Colombier 		       pdf_resource_type_t type,
809*593dc095SDavid du Colombier 		       pdf_font_resource_t **ppdfont,
810*593dc095SDavid du Colombier 		       pdf_char_glyph_pairs_t *cgp)
811*593dc095SDavid du Colombier {
812*593dc095SDavid du Colombier     pdf_resource_t **pchain = pdev->resources[type].chains;
813*593dc095SDavid du Colombier     pdf_resource_t *pres;
814*593dc095SDavid du Colombier     int i;
815*593dc095SDavid du Colombier 
816*593dc095SDavid du Colombier     for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
817*593dc095SDavid du Colombier 	for (pres = pchain[i]; pres != 0; pres = pres->next) {
818*593dc095SDavid du Colombier 	    pdf_font_resource_t *pdfont = (pdf_font_resource_t *)pres;
819*593dc095SDavid du Colombier 	    const gs_font_base *cfont;
820*593dc095SDavid du Colombier 	    gs_font *ofont = font;
821*593dc095SDavid du Colombier 	    int code;
822*593dc095SDavid du Colombier 
823*593dc095SDavid du Colombier 	    if (font->FontType != pdfont->FontType)
824*593dc095SDavid du Colombier 		continue;
825*593dc095SDavid du Colombier 	    if (pdfont->FontType == ft_composite) {
826*593dc095SDavid du Colombier 		gs_font_type0 *font0 = (gs_font_type0 *)font;
827*593dc095SDavid du Colombier 
828*593dc095SDavid du Colombier 		ofont = font0->data.FDepVector[0]; /* See pdf_make_font_resource. */
829*593dc095SDavid du Colombier 		cfont = pdf_font_resource_font(pdfont->u.type0.DescendantFont, false);
830*593dc095SDavid du Colombier 		if (font0->data.CMap->WMode != pdfont->u.type0.WMode)
831*593dc095SDavid du Colombier 		    continue;
832*593dc095SDavid du Colombier 	    } else
833*593dc095SDavid du Colombier 		cfont = pdf_font_resource_font(pdfont, false);
834*593dc095SDavid du Colombier 	    if (!pdf_is_CID_font(ofont) &&
835*593dc095SDavid du Colombier 		!pdf_is_compatible_encoding(pdev, pdfont, font, cgp->s, cgp->num_all_chars))
836*593dc095SDavid du Colombier 		continue;
837*593dc095SDavid du Colombier 	    if (cfont == 0)
838*593dc095SDavid du Colombier 		continue;
839*593dc095SDavid du Colombier 	    code = gs_copied_can_copy_glyphs((const gs_font *)cfont, ofont,
840*593dc095SDavid du Colombier 			    &cgp->s[cgp->unused_offset].glyph, cgp->num_unused_chars,
841*593dc095SDavid du Colombier 			    sizeof(pdf_char_glyph_pair_t), true);
842*593dc095SDavid du Colombier 	    if (code == gs_error_unregistered) /* Debug purpose only. */
843*593dc095SDavid du Colombier 		return code;
844*593dc095SDavid du Colombier 	    if(code > 0) {
845*593dc095SDavid du Colombier 		*ppdfont = pdfont;
846*593dc095SDavid du Colombier 		return 1;
847*593dc095SDavid du Colombier 	    }
848*593dc095SDavid du Colombier 	}
849*593dc095SDavid du Colombier     }
850*593dc095SDavid du Colombier     return 0;
851*593dc095SDavid du Colombier }
852*593dc095SDavid du Colombier 
853*593dc095SDavid du Colombier /*
854*593dc095SDavid du Colombier  * Find a type0 font resource for a gived descendent name and CMap name.
855*593dc095SDavid du Colombier  */
856*593dc095SDavid du Colombier private int
pdf_find_type0_font_resource(gx_device_pdf * pdev,const pdf_font_resource_t * pdsubf,const gs_const_string * CMapName,pdf_font_resource_t ** ppdfont)857*593dc095SDavid du Colombier pdf_find_type0_font_resource(gx_device_pdf *pdev, const pdf_font_resource_t *pdsubf,
858*593dc095SDavid du Colombier 	    const gs_const_string *CMapName, pdf_font_resource_t **ppdfont)
859*593dc095SDavid du Colombier {
860*593dc095SDavid du Colombier     pdf_resource_t **pchain = pdev->resources[resourceFont].chains;
861*593dc095SDavid du Colombier     pdf_resource_t *pres;
862*593dc095SDavid du Colombier     int i;
863*593dc095SDavid du Colombier 
864*593dc095SDavid du Colombier     for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
865*593dc095SDavid du Colombier 	for (pres = pchain[i]; pres != 0; pres = pres->next) {
866*593dc095SDavid du Colombier 	    pdf_font_resource_t *pdfont = (pdf_font_resource_t *)pres;
867*593dc095SDavid du Colombier 
868*593dc095SDavid du Colombier 	    if (pdfont->FontType != ft_composite)
869*593dc095SDavid du Colombier 		continue;
870*593dc095SDavid du Colombier 	    if (pdfont->u.type0.DescendantFont != pdsubf)
871*593dc095SDavid du Colombier 		continue;
872*593dc095SDavid du Colombier 	    if (pdfont->BaseFont.size != pdsubf->BaseFont.size + CMapName->size + 1)
873*593dc095SDavid du Colombier 		continue;
874*593dc095SDavid du Colombier 	    if (memcmp(pdfont->BaseFont.data + pdsubf->BaseFont.size + 1,
875*593dc095SDavid du Colombier 			CMapName->data, CMapName->size))
876*593dc095SDavid du Colombier 		continue;
877*593dc095SDavid du Colombier 	    *ppdfont = pdfont;
878*593dc095SDavid du Colombier 	    return 1;
879*593dc095SDavid du Colombier 	}
880*593dc095SDavid du Colombier     }
881*593dc095SDavid du Colombier     return 0;
882*593dc095SDavid du Colombier }
883*593dc095SDavid du Colombier 
884*593dc095SDavid du Colombier 
885*593dc095SDavid du Colombier private int pdf_make_font_resource(gx_device_pdf *pdev, gs_font *font,
886*593dc095SDavid du Colombier 		       pdf_font_resource_t **ppdfont,
887*593dc095SDavid du Colombier 		       pdf_char_glyph_pairs_t *cgp);
888*593dc095SDavid du Colombier 
889*593dc095SDavid du Colombier /*
890*593dc095SDavid du Colombier  * Create or find a CID font resource object for a glyph set.
891*593dc095SDavid du Colombier  */
892*593dc095SDavid du Colombier int
pdf_obtain_cidfont_resource(gx_device_pdf * pdev,gs_font * subfont,pdf_font_resource_t ** ppdsubf,pdf_char_glyph_pairs_t * cgp)893*593dc095SDavid du Colombier pdf_obtain_cidfont_resource(gx_device_pdf *pdev, gs_font *subfont,
894*593dc095SDavid du Colombier 			    pdf_font_resource_t **ppdsubf,
895*593dc095SDavid du Colombier 			    pdf_char_glyph_pairs_t *cgp)
896*593dc095SDavid du Colombier {
897*593dc095SDavid du Colombier     int code = 0;
898*593dc095SDavid du Colombier 
899*593dc095SDavid du Colombier     pdf_attached_font_resource(pdev, subfont, ppdsubf, NULL, NULL, NULL, NULL);
900*593dc095SDavid du Colombier     if (*ppdsubf != NULL) {
901*593dc095SDavid du Colombier 	const gs_font_base *cfont = pdf_font_resource_font(*ppdsubf, false);
902*593dc095SDavid du Colombier 
903*593dc095SDavid du Colombier 	code = gs_copied_can_copy_glyphs((const gs_font *)cfont, subfont,
904*593dc095SDavid du Colombier 			&cgp->s[cgp->unused_offset].glyph, cgp->num_unused_chars,
905*593dc095SDavid du Colombier 			sizeof(pdf_char_glyph_pair_t), true);
906*593dc095SDavid du Colombier 	if (code > 0)
907*593dc095SDavid du Colombier 	    return 0;
908*593dc095SDavid du Colombier 	if (code < 0)
909*593dc095SDavid du Colombier 	    return code;
910*593dc095SDavid du Colombier 	*ppdsubf = NULL;
911*593dc095SDavid du Colombier     }
912*593dc095SDavid du Colombier     code = pdf_find_font_resource(pdev, subfont,
913*593dc095SDavid du Colombier 				  resourceCIDFont, ppdsubf, cgp);
914*593dc095SDavid du Colombier     if (code < 0)
915*593dc095SDavid du Colombier 	return code;
916*593dc095SDavid du Colombier     if (*ppdsubf == NULL) {
917*593dc095SDavid du Colombier 	code = pdf_make_font_resource(pdev, subfont, ppdsubf, cgp);
918*593dc095SDavid du Colombier 	if (code < 0)
919*593dc095SDavid du Colombier 	    return code;
920*593dc095SDavid du Colombier     }
921*593dc095SDavid du Colombier     return pdf_attach_font_resource(pdev, subfont, *ppdsubf);
922*593dc095SDavid du Colombier }
923*593dc095SDavid du Colombier 
924*593dc095SDavid du Colombier /*
925*593dc095SDavid du Colombier  * Refine index of BaseEncoding.
926*593dc095SDavid du Colombier  */
927*593dc095SDavid du Colombier private int
pdf_refine_encoding_index(const gx_device_pdf * pdev,int index,bool is_standard)928*593dc095SDavid du Colombier pdf_refine_encoding_index(const gx_device_pdf *pdev, int index, bool is_standard)
929*593dc095SDavid du Colombier {
930*593dc095SDavid du Colombier     if (pdev->ForOPDFRead) {
931*593dc095SDavid du Colombier 	/*
932*593dc095SDavid du Colombier 	* Allow Postscript encodings only.
933*593dc095SDavid du Colombier 	*/
934*593dc095SDavid du Colombier 	switch (index) {
935*593dc095SDavid du Colombier 
936*593dc095SDavid du Colombier 	    case ENCODING_INDEX_STANDARD: return index;
937*593dc095SDavid du Colombier 	    case ENCODING_INDEX_ISOLATIN1: return index;
938*593dc095SDavid du Colombier 	    default:
939*593dc095SDavid du Colombier 		return ENCODING_INDEX_STANDARD;
940*593dc095SDavid du Colombier 	}
941*593dc095SDavid du Colombier     }
942*593dc095SDavid du Colombier     /*
943*593dc095SDavid du Colombier      * Per the PDF 1.3 documentation, there are only 3 BaseEncoding
944*593dc095SDavid du Colombier      * values allowed for non-embedded fonts.  Pick one here.
945*593dc095SDavid du Colombier      */
946*593dc095SDavid du Colombier     switch (index) {
947*593dc095SDavid du Colombier     case ENCODING_INDEX_WINANSI:
948*593dc095SDavid du Colombier     case ENCODING_INDEX_MACROMAN:
949*593dc095SDavid du Colombier     case ENCODING_INDEX_MACEXPERT:
950*593dc095SDavid du Colombier 	return index;
951*593dc095SDavid du Colombier     case ENCODING_INDEX_STANDARD:
952*593dc095SDavid du Colombier 	if (is_standard)
953*593dc095SDavid du Colombier 	    return index;
954*593dc095SDavid du Colombier 	/* Falls through. */
955*593dc095SDavid du Colombier     default:
956*593dc095SDavid du Colombier 	return ENCODING_INDEX_WINANSI;
957*593dc095SDavid du Colombier     }
958*593dc095SDavid du Colombier }
959*593dc095SDavid du Colombier 
960*593dc095SDavid du Colombier /*
961*593dc095SDavid du Colombier  * Create a font resource object for a gs_font of Type 3.
962*593dc095SDavid du Colombier  */
963*593dc095SDavid du Colombier int
pdf_make_font3_resource(gx_device_pdf * pdev,gs_font * font,pdf_font_resource_t ** ppdfont)964*593dc095SDavid du Colombier pdf_make_font3_resource(gx_device_pdf *pdev, gs_font *font,
965*593dc095SDavid du Colombier 		       pdf_font_resource_t **ppdfont)
966*593dc095SDavid du Colombier {
967*593dc095SDavid du Colombier     const gs_font_base *bfont = (const gs_font_base *)font;
968*593dc095SDavid du Colombier     pdf_font_resource_t *pdfont;
969*593dc095SDavid du Colombier     byte *cached;
970*593dc095SDavid du Colombier     int code;
971*593dc095SDavid du Colombier 
972*593dc095SDavid du Colombier     cached = gs_alloc_bytes(pdev->pdf_memory, 256/8, "pdf_make_font3_resource");
973*593dc095SDavid du Colombier     if (cached == NULL)
974*593dc095SDavid du Colombier 	return_error(gs_error_VMerror);
975*593dc095SDavid du Colombier     code = font_resource_encoded_alloc(pdev, &pdfont, bfont->id,
976*593dc095SDavid du Colombier 		    ft_user_defined, pdf_write_contents_bitmap);
977*593dc095SDavid du Colombier     if (code < 0) {
978*593dc095SDavid du Colombier 	gs_free_object(pdev->pdf_memory, cached, "pdf_make_font3_resource");
979*593dc095SDavid du Colombier 	return code;
980*593dc095SDavid du Colombier     }
981*593dc095SDavid du Colombier     memset(cached, 0, 256 / 8);
982*593dc095SDavid du Colombier     pdfont->u.simple.s.type3.bitmap_font = false;
983*593dc095SDavid du Colombier     pdfont->u.simple.BaseEncoding = pdf_refine_encoding_index(pdev,
984*593dc095SDavid du Colombier 			bfont->nearest_encoding_index, true);
985*593dc095SDavid du Colombier     pdfont->u.simple.s.type3.char_procs = NULL;
986*593dc095SDavid du Colombier     pdfont->u.simple.s.type3.cached = cached;
987*593dc095SDavid du Colombier     pdfont->u.simple.s.type3.FontBBox.p.x = (int)floor(bfont->FontBBox.p.x);
988*593dc095SDavid du Colombier     pdfont->u.simple.s.type3.FontBBox.p.y = (int)floor(bfont->FontBBox.p.y);
989*593dc095SDavid du Colombier     pdfont->u.simple.s.type3.FontBBox.q.x = (int)ceil(bfont->FontBBox.q.x);
990*593dc095SDavid du Colombier     pdfont->u.simple.s.type3.FontBBox.q.y = (int)ceil(bfont->FontBBox.q.y);
991*593dc095SDavid du Colombier     pdfont->u.simple.s.type3.FontMatrix = bfont->FontMatrix;
992*593dc095SDavid du Colombier     /* Adobe viewers have a precision problem with small font matrices : */
993*593dc095SDavid du Colombier     while (any_abs(pdfont->u.simple.s.type3.FontMatrix.xx) < 0.001 &&
994*593dc095SDavid du Colombier 	   any_abs(pdfont->u.simple.s.type3.FontMatrix.xy) < 0.001 &&
995*593dc095SDavid du Colombier 	   any_abs(pdfont->u.simple.s.type3.FontMatrix.yx) < 0.001 &&
996*593dc095SDavid du Colombier 	   any_abs(pdfont->u.simple.s.type3.FontMatrix.yy) < 0.001) {
997*593dc095SDavid du Colombier 	pdfont->u.simple.s.type3.FontMatrix.xx *= 10;
998*593dc095SDavid du Colombier 	pdfont->u.simple.s.type3.FontMatrix.xy *= 10;
999*593dc095SDavid du Colombier 	pdfont->u.simple.s.type3.FontMatrix.yx *= 10;
1000*593dc095SDavid du Colombier 	pdfont->u.simple.s.type3.FontMatrix.yy *= 10;
1001*593dc095SDavid du Colombier     }
1002*593dc095SDavid du Colombier     *ppdfont = pdfont;
1003*593dc095SDavid du Colombier     return 0;
1004*593dc095SDavid du Colombier }
1005*593dc095SDavid du Colombier 
1006*593dc095SDavid du Colombier /*
1007*593dc095SDavid du Colombier  * Create a font resource object for a gs_font.  Return 1 iff the
1008*593dc095SDavid du Colombier  * font was newly created (it's a roudiment, keeping reverse compatibility).
1009*593dc095SDavid du Colombier  * This procedure is only intended to be called
1010*593dc095SDavid du Colombier  * from a few places in the text code.
1011*593dc095SDavid du Colombier  */
1012*593dc095SDavid du Colombier private int
pdf_make_font_resource(gx_device_pdf * pdev,gs_font * font,pdf_font_resource_t ** ppdfont,pdf_char_glyph_pairs_t * cgp)1013*593dc095SDavid du Colombier pdf_make_font_resource(gx_device_pdf *pdev, gs_font *font,
1014*593dc095SDavid du Colombier 		       pdf_font_resource_t **ppdfont,
1015*593dc095SDavid du Colombier 		       pdf_char_glyph_pairs_t *cgp)
1016*593dc095SDavid du Colombier {
1017*593dc095SDavid du Colombier     int index = -1;
1018*593dc095SDavid du Colombier     int BaseEncoding = ENCODING_INDEX_UNKNOWN;
1019*593dc095SDavid du Colombier     pdf_font_embed_t embed;
1020*593dc095SDavid du Colombier     pdf_font_descriptor_t *pfd = 0;
1021*593dc095SDavid du Colombier     int (*font_alloc)(gx_device_pdf *, pdf_font_resource_t **,
1022*593dc095SDavid du Colombier 		      gs_id, pdf_font_descriptor_t *);
1023*593dc095SDavid du Colombier     gs_font *base_font = font; /* A roudiment from old code. Keep it for a while. */
1024*593dc095SDavid du Colombier     pdf_font_resource_t *pdfont;
1025*593dc095SDavid du Colombier     pdf_standard_font_t *const psfa =
1026*593dc095SDavid du Colombier 	pdev->text->outline_fonts->standard_fonts;
1027*593dc095SDavid du Colombier     int code = 0;
1028*593dc095SDavid du Colombier 
1029*593dc095SDavid du Colombier     if (pdev->version < psdf_version_level2_with_TT) {
1030*593dc095SDavid du Colombier 	switch(font->FontType) {
1031*593dc095SDavid du Colombier 	    case ft_TrueType:
1032*593dc095SDavid du Colombier 	    case ft_CID_TrueType:
1033*593dc095SDavid du Colombier 		return_error(gs_error_undefined);
1034*593dc095SDavid du Colombier 	    default:
1035*593dc095SDavid du Colombier 		break;
1036*593dc095SDavid du Colombier 	}
1037*593dc095SDavid du Colombier     }
1038*593dc095SDavid du Colombier     if (pdev->ForOPDFRead && !pdev->HaveCIDSystem) {
1039*593dc095SDavid du Colombier 	switch(font->FontType) {
1040*593dc095SDavid du Colombier 	    case ft_CID_encrypted:
1041*593dc095SDavid du Colombier 	    case ft_CID_TrueType:
1042*593dc095SDavid du Colombier 		return_error(gs_error_undefined);
1043*593dc095SDavid du Colombier 	    default:
1044*593dc095SDavid du Colombier 		break;
1045*593dc095SDavid du Colombier 	}
1046*593dc095SDavid du Colombier     }
1047*593dc095SDavid du Colombier     if (!pdev->HaveCFF) {
1048*593dc095SDavid du Colombier 	if (font->FontType == ft_encrypted2)
1049*593dc095SDavid du Colombier 	    return_error(gs_error_undefined);
1050*593dc095SDavid du Colombier     }
1051*593dc095SDavid du Colombier     embed = pdf_font_embed_status(pdev, base_font, &index, cgp->s, cgp->num_all_chars);
1052*593dc095SDavid du Colombier     if (embed == FONT_EMBED_STANDARD) {
1053*593dc095SDavid du Colombier 	pdf_standard_font_t *psf = &psfa[index];
1054*593dc095SDavid du Colombier 
1055*593dc095SDavid du Colombier 	if (psf->pdfont == NULL ||
1056*593dc095SDavid du Colombier 		!pdf_is_compatible_encoding(pdev, psf->pdfont, font,
1057*593dc095SDavid du Colombier 			cgp->s, cgp->num_all_chars)) {
1058*593dc095SDavid du Colombier 	    code = pdf_font_std_alloc(pdev, ppdfont, (psf->pdfont == NULL), base_font->id,
1059*593dc095SDavid du Colombier 				      (gs_font_base *)base_font, index);
1060*593dc095SDavid du Colombier 	    if (code < 0)
1061*593dc095SDavid du Colombier 		return code;
1062*593dc095SDavid du Colombier 	    if (psf->pdfont == NULL)
1063*593dc095SDavid du Colombier 		psf->pdfont = *ppdfont;
1064*593dc095SDavid du Colombier 	    (*ppdfont)->u.simple.BaseEncoding = pdf_refine_encoding_index(pdev,
1065*593dc095SDavid du Colombier 		((const gs_font_base *)base_font)->nearest_encoding_index, true);
1066*593dc095SDavid du Colombier 	    code = 1;
1067*593dc095SDavid du Colombier 	} else
1068*593dc095SDavid du Colombier 	    *ppdfont = psf->pdfont;
1069*593dc095SDavid du Colombier 	return code;
1070*593dc095SDavid du Colombier     }
1071*593dc095SDavid du Colombier 
1072*593dc095SDavid du Colombier     switch (font->FontType) {
1073*593dc095SDavid du Colombier     case ft_CID_encrypted:
1074*593dc095SDavid du Colombier     case ft_CID_TrueType:
1075*593dc095SDavid du Colombier 	font_alloc = pdf_font_cidfont_alloc;
1076*593dc095SDavid du Colombier 	break;
1077*593dc095SDavid du Colombier     case ft_encrypted:
1078*593dc095SDavid du Colombier     case ft_encrypted2:
1079*593dc095SDavid du Colombier     case ft_TrueType:
1080*593dc095SDavid du Colombier 	font_alloc = pdf_font_simple_alloc;
1081*593dc095SDavid du Colombier 	break;
1082*593dc095SDavid du Colombier     case ft_user_defined:
1083*593dc095SDavid du Colombier 	code = pdf_make_font3_resource(pdev, font, ppdfont);
1084*593dc095SDavid du Colombier 	if (code < 0)
1085*593dc095SDavid du Colombier 	    return code;
1086*593dc095SDavid du Colombier 	return 1;
1087*593dc095SDavid du Colombier     default:
1088*593dc095SDavid du Colombier 	return_error(gs_error_invalidfont);
1089*593dc095SDavid du Colombier     }
1090*593dc095SDavid du Colombier 
1091*593dc095SDavid du Colombier     /* Create an appropriate font resource and descriptor. */
1092*593dc095SDavid du Colombier     if (embed == FONT_EMBED_YES) {
1093*593dc095SDavid du Colombier 	/*
1094*593dc095SDavid du Colombier 	 * HACK: Acrobat Reader 3 has a bug that makes cmap formats 4
1095*593dc095SDavid du Colombier 	 * and 6 not work in embedded TrueType fonts.  Consequently, it
1096*593dc095SDavid du Colombier 	 * can only handle embedded TrueType fonts if all the glyphs
1097*593dc095SDavid du Colombier 	 * referenced by the Encoding have numbers 0-255.  Check for
1098*593dc095SDavid du Colombier 	 * this now.
1099*593dc095SDavid du Colombier 	 */
1100*593dc095SDavid du Colombier 	if (font->FontType == ft_TrueType &&
1101*593dc095SDavid du Colombier 	    pdev->CompatibilityLevel <= 1.2
1102*593dc095SDavid du Colombier 	    ) {
1103*593dc095SDavid du Colombier 	    int i;
1104*593dc095SDavid du Colombier 
1105*593dc095SDavid du Colombier 	    for (i = 0; i <= 0xff; ++i) {
1106*593dc095SDavid du Colombier 		gs_glyph glyph =
1107*593dc095SDavid du Colombier 		    font->procs.encode_char(font, (gs_char)i,
1108*593dc095SDavid du Colombier 					    GLYPH_SPACE_INDEX);
1109*593dc095SDavid du Colombier 
1110*593dc095SDavid du Colombier 		if (glyph == GS_NO_GLYPH ||
1111*593dc095SDavid du Colombier 		    (glyph >= GS_MIN_GLYPH_INDEX &&
1112*593dc095SDavid du Colombier 		     glyph <= GS_MIN_GLYPH_INDEX + 0xff)
1113*593dc095SDavid du Colombier 		    )
1114*593dc095SDavid du Colombier 		    continue;
1115*593dc095SDavid du Colombier 		/* Can't embed, punt. */
1116*593dc095SDavid du Colombier 		return_error(gs_error_rangecheck);
1117*593dc095SDavid du Colombier 	    }
1118*593dc095SDavid du Colombier 	}
1119*593dc095SDavid du Colombier     }
1120*593dc095SDavid du Colombier     if (font->FontType == ft_encrypted || font->FontType == ft_encrypted2 ||
1121*593dc095SDavid du Colombier 	font->FontType == ft_TrueType) {
1122*593dc095SDavid du Colombier         /*
1123*593dc095SDavid du Colombier 	 * We write True Types with Symbolic flag set.
1124*593dc095SDavid du Colombier 	 * PDF spec says that "symbolic font should not specify Encoding entry"
1125*593dc095SDavid du Colombier 	 * (see section 5.5, the article "Encodings for True Type fonts", paragraph 3).
1126*593dc095SDavid du Colombier 	 * However Acrobat Reader 4,5,6 fail when TT font with no Encoding
1127*593dc095SDavid du Colombier 	 * appears in a document together with a CID font with a non-standard CMap
1128*593dc095SDavid du Colombier 	 * (AR 4 and 5 claim "The encoding (CMap) specified by a font is corrupted."
1129*593dc095SDavid du Colombier 	 * (we read it as "The encoding or CMap specified by a font is corrupted.",
1130*593dc095SDavid du Colombier 	 * and apply the 1st alternative)). We believe that AR is buggy,
1131*593dc095SDavid du Colombier 	 * and therefore we write an Encoding with non-CID True Type fonts.
1132*593dc095SDavid du Colombier 	 * Hopely other viewers can ignore Encoding in such case. Actually in this case
1133*593dc095SDavid du Colombier 	 * an Encoding doesn't add an useful information.
1134*593dc095SDavid du Colombier 	 */
1135*593dc095SDavid du Colombier 	BaseEncoding = pdf_refine_encoding_index(pdev,
1136*593dc095SDavid du Colombier 	    ((const gs_font_base *)base_font)->nearest_encoding_index, false);
1137*593dc095SDavid du Colombier     }
1138*593dc095SDavid du Colombier     if ((code = pdf_font_descriptor_alloc(pdev, &pfd,
1139*593dc095SDavid du Colombier 					  (gs_font_base *)base_font,
1140*593dc095SDavid du Colombier 					  embed == FONT_EMBED_YES)) < 0 ||
1141*593dc095SDavid du Colombier 	(code = font_alloc(pdev, &pdfont, base_font->id, pfd)) < 0
1142*593dc095SDavid du Colombier 	)
1143*593dc095SDavid du Colombier 	return code;
1144*593dc095SDavid du Colombier     code = 1;
1145*593dc095SDavid du Colombier 
1146*593dc095SDavid du Colombier     if (!pdf_is_CID_font(font))
1147*593dc095SDavid du Colombier 	pdfont->u.simple.BaseEncoding = BaseEncoding;
1148*593dc095SDavid du Colombier 
1149*593dc095SDavid du Colombier     *ppdfont = pdfont;
1150*593dc095SDavid du Colombier     return 1;
1151*593dc095SDavid du Colombier }
1152*593dc095SDavid du Colombier 
1153*593dc095SDavid du Colombier /* Get a synthesized Type 3 font scale. */
1154*593dc095SDavid du Colombier void
pdf_font3_scale(gx_device_pdf * pdev,gs_font * font,double * scale)1155*593dc095SDavid du Colombier pdf_font3_scale(gx_device_pdf *pdev, gs_font *font, double *scale)
1156*593dc095SDavid du Colombier {
1157*593dc095SDavid du Colombier     pdf_font_resource_t *pdfont;
1158*593dc095SDavid du Colombier 
1159*593dc095SDavid du Colombier     pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
1160*593dc095SDavid du Colombier     *scale = pdfont->u.simple.s.type3.FontMatrix.xx;
1161*593dc095SDavid du Colombier }
1162*593dc095SDavid du Colombier 
1163*593dc095SDavid du Colombier /*
1164*593dc095SDavid du Colombier  * Check for simple font.
1165*593dc095SDavid du Colombier  */
1166*593dc095SDavid du Colombier bool
pdf_is_simple_font(gs_font * font)1167*593dc095SDavid du Colombier pdf_is_simple_font(gs_font *font)
1168*593dc095SDavid du Colombier {
1169*593dc095SDavid du Colombier     return (font->FontType == ft_encrypted ||
1170*593dc095SDavid du Colombier 	    font->FontType == ft_encrypted2 ||
1171*593dc095SDavid du Colombier 	    font->FontType == ft_TrueType ||
1172*593dc095SDavid du Colombier 	    font->FontType == ft_user_defined);
1173*593dc095SDavid du Colombier }
1174*593dc095SDavid du Colombier 
1175*593dc095SDavid du Colombier /*
1176*593dc095SDavid du Colombier  * Check for CID font.
1177*593dc095SDavid du Colombier  */
1178*593dc095SDavid du Colombier bool
pdf_is_CID_font(gs_font * font)1179*593dc095SDavid du Colombier pdf_is_CID_font(gs_font *font)
1180*593dc095SDavid du Colombier {
1181*593dc095SDavid du Colombier     return (font->FontType == ft_CID_encrypted ||
1182*593dc095SDavid du Colombier 	    font->FontType == ft_CID_TrueType);
1183*593dc095SDavid du Colombier }
1184*593dc095SDavid du Colombier 
1185*593dc095SDavid du Colombier /*
1186*593dc095SDavid du Colombier  * Enumerate glyphs for a text.
1187*593dc095SDavid du Colombier  */
1188*593dc095SDavid du Colombier private int
pdf_next_char_glyph(gs_text_enum_t * penum,const gs_string * pstr,gs_font * font,bool font_is_simple,gs_char * char_code,gs_char * cid,gs_glyph * glyph)1189*593dc095SDavid du Colombier pdf_next_char_glyph(gs_text_enum_t *penum, const gs_string *pstr,
1190*593dc095SDavid du Colombier 	       /* const */ gs_font *font, bool font_is_simple,
1191*593dc095SDavid du Colombier 	       gs_char *char_code, gs_char *cid, gs_glyph *glyph)
1192*593dc095SDavid du Colombier {
1193*593dc095SDavid du Colombier     int code = font->procs.next_char_glyph(penum, char_code, glyph);
1194*593dc095SDavid du Colombier 
1195*593dc095SDavid du Colombier     if (code == 2)		/* end of string */
1196*593dc095SDavid du Colombier 	return code;
1197*593dc095SDavid du Colombier     if (code < 0)
1198*593dc095SDavid du Colombier 	return code;
1199*593dc095SDavid du Colombier     if (font_is_simple) {
1200*593dc095SDavid du Colombier 	*cid = *char_code;
1201*593dc095SDavid du Colombier 	*glyph = font->procs.encode_char(font, *char_code, GLYPH_SPACE_NAME);
1202*593dc095SDavid du Colombier 	if (*glyph == GS_NO_GLYPH)
1203*593dc095SDavid du Colombier 	    return 3;
1204*593dc095SDavid du Colombier     } else {
1205*593dc095SDavid du Colombier 	if (*glyph < GS_MIN_CID_GLYPH)
1206*593dc095SDavid du Colombier 	    return 3; /* Not sure why, copied from scan_cmap_text. */
1207*593dc095SDavid du Colombier 	*cid = *glyph - GS_MIN_CID_GLYPH; /* CID */
1208*593dc095SDavid du Colombier     }
1209*593dc095SDavid du Colombier     return 0;
1210*593dc095SDavid du Colombier }
1211*593dc095SDavid du Colombier 
1212*593dc095SDavid du Colombier private void
store_glyphs(pdf_char_glyph_pairs_t * cgp,byte * glyph_usage,int char_cache_size,gs_char char_code,gs_char cid,gs_glyph glyph)1213*593dc095SDavid du Colombier store_glyphs(pdf_char_glyph_pairs_t *cgp,
1214*593dc095SDavid du Colombier 	     byte *glyph_usage, int char_cache_size,
1215*593dc095SDavid du Colombier 	     gs_char char_code, gs_char cid, gs_glyph glyph)
1216*593dc095SDavid du Colombier {
1217*593dc095SDavid du Colombier     int j;
1218*593dc095SDavid du Colombier 
1219*593dc095SDavid du Colombier     for (j = 0; j < cgp->num_all_chars; j++)
1220*593dc095SDavid du Colombier 	if (cgp->s[j].chr == cid)
1221*593dc095SDavid du Colombier 	    break;
1222*593dc095SDavid du Colombier     if (j < cgp->num_all_chars)
1223*593dc095SDavid du Colombier 	return;
1224*593dc095SDavid du Colombier     cgp->s[cgp->num_all_chars].glyph = glyph;
1225*593dc095SDavid du Colombier     cgp->s[cgp->num_all_chars].chr = char_code;
1226*593dc095SDavid du Colombier     cgp->num_all_chars++;
1227*593dc095SDavid du Colombier     if (glyph_usage == 0 || !(glyph_usage[cid / 8] & (0x80 >> (cid & 7)))) {
1228*593dc095SDavid du Colombier 	cgp->s[cgp->unused_offset + cgp->num_unused_chars].glyph = glyph;
1229*593dc095SDavid du Colombier     	cgp->s[cgp->unused_offset + cgp->num_unused_chars].chr = char_code;
1230*593dc095SDavid du Colombier 	cgp->num_unused_chars++;
1231*593dc095SDavid du Colombier     }
1232*593dc095SDavid du Colombier     /* We are disliked that gs_copied_can_copy_glyphs can get redundant
1233*593dc095SDavid du Colombier      * glyphs, if Encoding specifies several codes for same glyph.
1234*593dc095SDavid du Colombier      * But we need the positional correspondence
1235*593dc095SDavid du Colombier      * of glyphs to codes for pdf_is_compatible_encoding.
1236*593dc095SDavid du Colombier      * Redundant glyphs isn't a big payment for it
1237*593dc095SDavid du Colombier      * because they happen seldom.
1238*593dc095SDavid du Colombier      */
1239*593dc095SDavid du Colombier }
1240*593dc095SDavid du Colombier 
1241*593dc095SDavid du Colombier /* Allocate storage for the glyph set of the text. */
1242*593dc095SDavid du Colombier private int
pdf_alloc_text_glyphs_table(gx_device_pdf * pdev,pdf_text_enum_t * penum,const gs_string * pstr)1243*593dc095SDavid du Colombier pdf_alloc_text_glyphs_table(gx_device_pdf *pdev, pdf_text_enum_t *penum, const gs_string *pstr)
1244*593dc095SDavid du Colombier {
1245*593dc095SDavid du Colombier     const int go = (pstr != NULL ? pstr->size : penum->text.size);
1246*593dc095SDavid du Colombier     const int struct_size = sizeof(pdf_char_glyph_pairs_t) +
1247*593dc095SDavid du Colombier 			    sizeof(pdf_char_glyph_pair_t) * (2 * go - 1);
1248*593dc095SDavid du Colombier     pdf_char_glyph_pairs_t *cgp = (pdf_char_glyph_pairs_t *)gs_alloc_bytes(penum->memory,
1249*593dc095SDavid du Colombier 		struct_size, "pdf_alloc_text_glyphs_table");
1250*593dc095SDavid du Colombier     if (cgp == NULL)
1251*593dc095SDavid du Colombier 	return_error(gs_error_VMerror);
1252*593dc095SDavid du Colombier     penum->cgp = cgp;
1253*593dc095SDavid du Colombier     cgp->unused_offset = go;
1254*593dc095SDavid du Colombier     cgp->num_all_chars = 0;
1255*593dc095SDavid du Colombier     cgp->num_unused_chars = 0;
1256*593dc095SDavid du Colombier     return 0;
1257*593dc095SDavid du Colombier }
1258*593dc095SDavid du Colombier 
1259*593dc095SDavid du Colombier /* Build the glyph set of the text. */
1260*593dc095SDavid du Colombier private int
pdf_make_text_glyphs_table(pdf_text_enum_t * penum,const gs_string * pstr,byte * glyph_usage,int char_cache_size)1261*593dc095SDavid du Colombier pdf_make_text_glyphs_table(pdf_text_enum_t *penum, const gs_string *pstr,
1262*593dc095SDavid du Colombier 		byte *glyph_usage, int char_cache_size)
1263*593dc095SDavid du Colombier {
1264*593dc095SDavid du Colombier     gs_text_enum_t scan = *(gs_text_enum_t *)penum;
1265*593dc095SDavid du Colombier     gs_font *font = (gs_font *)penum->current_font;
1266*593dc095SDavid du Colombier     bool font_is_simple = pdf_is_simple_font(font);
1267*593dc095SDavid du Colombier     pdf_char_glyph_pairs_t *cgp = penum->cgp;
1268*593dc095SDavid du Colombier     gs_char char_code, cid;
1269*593dc095SDavid du Colombier     gs_glyph glyph;
1270*593dc095SDavid du Colombier     int code;
1271*593dc095SDavid du Colombier 
1272*593dc095SDavid du Colombier     cgp->num_unused_chars = 0;
1273*593dc095SDavid du Colombier     cgp->num_all_chars = 0;
1274*593dc095SDavid du Colombier     if (pstr != NULL) {
1275*593dc095SDavid du Colombier 	scan.text.data.bytes = pstr->data;
1276*593dc095SDavid du Colombier 	scan.text.size = pstr->size;
1277*593dc095SDavid du Colombier 	scan.index = 0;
1278*593dc095SDavid du Colombier         /* if TEXT_FROM_CHARS the data was converted to bytes earlier */
1279*593dc095SDavid du Colombier         if ( scan.text.operation & TEXT_FROM_CHARS )
1280*593dc095SDavid du Colombier             scan.text.operation = ((scan.text.operation & ~TEXT_FROM_CHARS) | TEXT_FROM_STRING);
1281*593dc095SDavid du Colombier     }
1282*593dc095SDavid du Colombier     for (;;) {
1283*593dc095SDavid du Colombier 	code = pdf_next_char_glyph(&scan, pstr, font, font_is_simple,
1284*593dc095SDavid du Colombier 				   &char_code, &cid, &glyph);
1285*593dc095SDavid du Colombier 	if (code == 2)		/* end of string */
1286*593dc095SDavid du Colombier 	    break;
1287*593dc095SDavid du Colombier 	if (code == 3)		/* no glyph */
1288*593dc095SDavid du Colombier 	    continue;
1289*593dc095SDavid du Colombier 	if (code < 0)
1290*593dc095SDavid du Colombier 	    return code;
1291*593dc095SDavid du Colombier 	if (cgp->num_all_chars > cgp->unused_offset)
1292*593dc095SDavid du Colombier 	    return_error(gs_error_unregistered); /* Must not happen. */
1293*593dc095SDavid du Colombier 	if (glyph_usage != 0 && cid > char_cache_size)
1294*593dc095SDavid du Colombier 	    continue;
1295*593dc095SDavid du Colombier 	store_glyphs(cgp, glyph_usage, char_cache_size,
1296*593dc095SDavid du Colombier 		     char_code, cid, glyph);
1297*593dc095SDavid du Colombier     }
1298*593dc095SDavid du Colombier     return 0;
1299*593dc095SDavid du Colombier }
1300*593dc095SDavid du Colombier 
1301*593dc095SDavid du Colombier /* Build the glyph set of the glyphshow text, and re_encode the text. */
1302*593dc095SDavid du Colombier private int
pdf_make_text_glyphs_table_unencoded(pdf_char_glyph_pairs_t * cgp,gs_font * font,const gs_string * pstr,const gs_glyph * gdata,int * ps_encoding_index)1303*593dc095SDavid du Colombier pdf_make_text_glyphs_table_unencoded(pdf_char_glyph_pairs_t *cgp,
1304*593dc095SDavid du Colombier 		gs_font *font, const gs_string *pstr, const gs_glyph *gdata,
1305*593dc095SDavid du Colombier 		int *ps_encoding_index)
1306*593dc095SDavid du Colombier {
1307*593dc095SDavid du Colombier     int i, ei;
1308*593dc095SDavid du Colombier     gs_char ch;
1309*593dc095SDavid du Colombier     gs_const_string gname;
1310*593dc095SDavid du Colombier     gs_glyph *gid = (gs_glyph *)pstr->data; /* pdf_text_process allocs enough space. */
1311*593dc095SDavid du Colombier 
1312*593dc095SDavid du Colombier     /* Translate glyph name indices into gscencs.c indices. */
1313*593dc095SDavid du Colombier     for (i = 0; i < pstr->size; i++) {
1314*593dc095SDavid du Colombier 	int code = font->procs.glyph_name(font, gdata[i], &gname);
1315*593dc095SDavid du Colombier 
1316*593dc095SDavid du Colombier 	if (code < 0)
1317*593dc095SDavid du Colombier 	    return code;
1318*593dc095SDavid du Colombier 	gid[i] = gs_c_name_glyph(gname.data, gname.size);
1319*593dc095SDavid du Colombier 	if (gid[i] == GS_NO_GLYPH)
1320*593dc095SDavid du Colombier 	    return_error(gs_error_rangecheck);
1321*593dc095SDavid du Colombier     }
1322*593dc095SDavid du Colombier 
1323*593dc095SDavid du Colombier     /* Find an acceptable encodng. */
1324*593dc095SDavid du Colombier     for (ei = 0; gs_c_known_encodings[ei]; ei++) {
1325*593dc095SDavid du Colombier 	cgp->num_unused_chars = 0;
1326*593dc095SDavid du Colombier 	cgp->num_all_chars = 0;
1327*593dc095SDavid du Colombier 	for (i = 0; i < pstr->size; i++) {
1328*593dc095SDavid du Colombier 	    ch = gs_c_decode(gid[i], ei);
1329*593dc095SDavid du Colombier 	    if (ch == GS_NO_CHAR)
1330*593dc095SDavid du Colombier 		break;
1331*593dc095SDavid du Colombier 	    /* pstr->data[i] = (byte)ch; Can't do because pstr->data and gid
1332*593dc095SDavid du Colombier 	       are same pointer. Will do in a separate pass below. */
1333*593dc095SDavid du Colombier 	    store_glyphs(cgp, NULL, 0,
1334*593dc095SDavid du Colombier 			 ch, ch, gdata[i]);
1335*593dc095SDavid du Colombier 	}
1336*593dc095SDavid du Colombier 	*ps_encoding_index = ei;
1337*593dc095SDavid du Colombier 	if (i == pstr->size) {
1338*593dc095SDavid du Colombier 	    for (i = 0; i < pstr->size; i++)
1339*593dc095SDavid du Colombier 		pstr->data[i] = (byte)gs_c_decode(gid[i], ei);
1340*593dc095SDavid du Colombier 	    return 0;
1341*593dc095SDavid du Colombier 	}
1342*593dc095SDavid du Colombier     }
1343*593dc095SDavid du Colombier     return_error(gs_error_rangecheck);
1344*593dc095SDavid du Colombier }
1345*593dc095SDavid du Colombier 
1346*593dc095SDavid du Colombier 
1347*593dc095SDavid du Colombier /* Get/make font resource for the font with a known encoding. */
1348*593dc095SDavid du Colombier private int
pdf_obtain_font_resource_encoded(gx_device_pdf * pdev,gs_font * font,pdf_font_resource_t ** ppdfont,pdf_char_glyph_pairs_t * cgp)1349*593dc095SDavid du Colombier pdf_obtain_font_resource_encoded(gx_device_pdf *pdev, gs_font *font,
1350*593dc095SDavid du Colombier 	pdf_font_resource_t **ppdfont, pdf_char_glyph_pairs_t *cgp)
1351*593dc095SDavid du Colombier {
1352*593dc095SDavid du Colombier     int code;
1353*593dc095SDavid du Colombier     pdf_font_resource_t *pdfont_not_allowed = NULL;
1354*593dc095SDavid du Colombier 
1355*593dc095SDavid du Colombier     if (*ppdfont != 0) {
1356*593dc095SDavid du Colombier 	gs_font_base *cfont = pdf_font_resource_font(*ppdfont, false);
1357*593dc095SDavid du Colombier 
1358*593dc095SDavid du Colombier 	if (font->FontType != ft_user_defined) {
1359*593dc095SDavid du Colombier 	    code = gs_copied_can_copy_glyphs((gs_font *)cfont, font,
1360*593dc095SDavid du Colombier 			&cgp->s[cgp->unused_offset].glyph, cgp->num_unused_chars,
1361*593dc095SDavid du Colombier 			sizeof(pdf_char_glyph_pair_t), true);
1362*593dc095SDavid du Colombier 	    if (code < 0)
1363*593dc095SDavid du Colombier 		return code;
1364*593dc095SDavid du Colombier 	} else
1365*593dc095SDavid du Colombier 	    code = 1;
1366*593dc095SDavid du Colombier 	if (code == 0) {
1367*593dc095SDavid du Colombier 	    pdfont_not_allowed = *ppdfont;
1368*593dc095SDavid du Colombier 	    *ppdfont = 0;
1369*593dc095SDavid du Colombier 	} else if(!pdf_is_compatible_encoding(pdev, *ppdfont, font,
1370*593dc095SDavid du Colombier 			cgp->s, cgp->num_all_chars)) {
1371*593dc095SDavid du Colombier 	    pdfont_not_allowed = *ppdfont;
1372*593dc095SDavid du Colombier 	    *ppdfont = 0;
1373*593dc095SDavid du Colombier 	}
1374*593dc095SDavid du Colombier     }
1375*593dc095SDavid du Colombier     if (*ppdfont == 0) {
1376*593dc095SDavid du Colombier 	gs_font *base_font = font;
1377*593dc095SDavid du Colombier 	gs_font *below;
1378*593dc095SDavid du Colombier 	bool same_encoding = true;
1379*593dc095SDavid du Colombier 
1380*593dc095SDavid du Colombier 	/*
1381*593dc095SDavid du Colombier 	 * Find the "lowest" base font that has the same outlines.
1382*593dc095SDavid du Colombier 	 * We use its FontName for font resource.
1383*593dc095SDavid du Colombier 	 */
1384*593dc095SDavid du Colombier 	while ((below = base_font->base) != base_font &&
1385*593dc095SDavid du Colombier 	       base_font->procs.same_font(base_font, below, FONT_SAME_OUTLINES))
1386*593dc095SDavid du Colombier 	    base_font = below;
1387*593dc095SDavid du Colombier 	if (base_font != font)
1388*593dc095SDavid du Colombier 	    same_encoding = ((base_font->procs.same_font(base_font, font,
1389*593dc095SDavid du Colombier 	                      FONT_SAME_ENCODING) & FONT_SAME_ENCODING) != 0);
1390*593dc095SDavid du Colombier 	/* Find or make font resource. */
1391*593dc095SDavid du Colombier 	pdf_attached_font_resource(pdev, base_font, ppdfont, NULL, NULL, NULL, NULL);
1392*593dc095SDavid du Colombier 	if (*ppdfont != NULL && base_font != font) {
1393*593dc095SDavid du Colombier 	    if (pdfont_not_allowed == *ppdfont)
1394*593dc095SDavid du Colombier 		*ppdfont = NULL;
1395*593dc095SDavid du Colombier 	    else if(!pdf_is_compatible_encoding(pdev, *ppdfont,
1396*593dc095SDavid du Colombier 				    base_font, cgp->s, cgp->num_all_chars))
1397*593dc095SDavid du Colombier 		*ppdfont = NULL;
1398*593dc095SDavid du Colombier 	}
1399*593dc095SDavid du Colombier 	if (*ppdfont == NULL || *ppdfont == pdfont_not_allowed) {
1400*593dc095SDavid du Colombier 	    pdf_resource_type_t type =
1401*593dc095SDavid du Colombier 		(pdf_is_CID_font(base_font) ? resourceCIDFont
1402*593dc095SDavid du Colombier 					    : resourceFont);
1403*593dc095SDavid du Colombier 	    *ppdfont = NULL;
1404*593dc095SDavid du Colombier     	    code = pdf_find_font_resource(pdev, base_font, type, ppdfont, cgp);
1405*593dc095SDavid du Colombier 	    if (code < 0)
1406*593dc095SDavid du Colombier 		return code;
1407*593dc095SDavid du Colombier 	    if (*ppdfont == NULL) {
1408*593dc095SDavid du Colombier 		code = pdf_make_font_resource(pdev, base_font, ppdfont, cgp);
1409*593dc095SDavid du Colombier 		if (code < 0)
1410*593dc095SDavid du Colombier 		    return code;
1411*593dc095SDavid du Colombier 	    }
1412*593dc095SDavid du Colombier 	    if (base_font != font && same_encoding) {
1413*593dc095SDavid du Colombier 		code = pdf_attach_font_resource(pdev, base_font, *ppdfont);
1414*593dc095SDavid du Colombier 		if (code < 0)
1415*593dc095SDavid du Colombier 		    return code;
1416*593dc095SDavid du Colombier 	    }
1417*593dc095SDavid du Colombier 	}
1418*593dc095SDavid du Colombier 	code = pdf_attach_font_resource(pdev, font, *ppdfont);
1419*593dc095SDavid du Colombier 	if (code < 0)
1420*593dc095SDavid du Colombier 	    return code;
1421*593dc095SDavid du Colombier     }
1422*593dc095SDavid du Colombier     return 0;
1423*593dc095SDavid du Colombier }
1424*593dc095SDavid du Colombier 
1425*593dc095SDavid du Colombier /* Mark glyphs used in the text with the font resource. */
1426*593dc095SDavid du Colombier private int
pdf_mark_text_glyphs(const gs_text_enum_t * penum,const gs_string * pstr,byte * glyph_usage,int char_cache_size)1427*593dc095SDavid du Colombier pdf_mark_text_glyphs(const gs_text_enum_t *penum, const gs_string *pstr,
1428*593dc095SDavid du Colombier 	    byte *glyph_usage, int char_cache_size)
1429*593dc095SDavid du Colombier {
1430*593dc095SDavid du Colombier     gs_text_enum_t scan = *penum;
1431*593dc095SDavid du Colombier     gs_font *font = (gs_font *)penum->current_font;
1432*593dc095SDavid du Colombier     bool font_is_simple = pdf_is_simple_font(font);
1433*593dc095SDavid du Colombier     gs_char char_code, cid;
1434*593dc095SDavid du Colombier     gs_glyph glyph;
1435*593dc095SDavid du Colombier 
1436*593dc095SDavid du Colombier     if (pstr != NULL) {
1437*593dc095SDavid du Colombier 	scan.text.data.bytes = pstr->data;
1438*593dc095SDavid du Colombier 	scan.text.size = pstr->size;
1439*593dc095SDavid du Colombier 	scan.index = 0;
1440*593dc095SDavid du Colombier         /* if TEXT_FROM_CHARS the data was converted to bytes earlier */
1441*593dc095SDavid du Colombier         if ( scan.text.operation & TEXT_FROM_CHARS )
1442*593dc095SDavid du Colombier             scan.text.operation =
1443*593dc095SDavid du Colombier                 ((scan.text.operation & ~TEXT_FROM_CHARS) | TEXT_FROM_STRING);
1444*593dc095SDavid du Colombier     }
1445*593dc095SDavid du Colombier     for (;;) {
1446*593dc095SDavid du Colombier 	int code = pdf_next_char_glyph(&scan, pstr, font, font_is_simple,
1447*593dc095SDavid du Colombier 				       &char_code, &cid, &glyph);
1448*593dc095SDavid du Colombier 
1449*593dc095SDavid du Colombier 	if (code == 2)		/* end of string */
1450*593dc095SDavid du Colombier 	    break;
1451*593dc095SDavid du Colombier 	if (code == 3)		/* no glyph */
1452*593dc095SDavid du Colombier 	    continue;
1453*593dc095SDavid du Colombier 	if (code < 0)
1454*593dc095SDavid du Colombier 	    return code;
1455*593dc095SDavid du Colombier 	if (glyph_usage != 0 && cid >= char_cache_size)
1456*593dc095SDavid du Colombier 	    continue;
1457*593dc095SDavid du Colombier 	glyph_usage[cid / 8] |= 0x80 >> (cid & 7);
1458*593dc095SDavid du Colombier     }
1459*593dc095SDavid du Colombier     return 0;
1460*593dc095SDavid du Colombier }
1461*593dc095SDavid du Colombier 
1462*593dc095SDavid du Colombier /* Mark glyphs used in the glyphshow text with the font resource. */
1463*593dc095SDavid du Colombier private int
pdf_mark_text_glyphs_unencoded(const gs_text_enum_t * penum,const gs_string * pstr,byte * glyph_usage,int char_cache_size)1464*593dc095SDavid du Colombier pdf_mark_text_glyphs_unencoded(const gs_text_enum_t *penum, const gs_string *pstr,
1465*593dc095SDavid du Colombier 	    byte *glyph_usage, int char_cache_size)
1466*593dc095SDavid du Colombier {
1467*593dc095SDavid du Colombier     int i;
1468*593dc095SDavid du Colombier 
1469*593dc095SDavid du Colombier     for(i = 0; i < pstr->size; i++) {
1470*593dc095SDavid du Colombier 	byte ch = pstr->data[i];
1471*593dc095SDavid du Colombier 
1472*593dc095SDavid du Colombier 	if (ch >= char_cache_size)
1473*593dc095SDavid du Colombier 	    return_error(gs_error_rangecheck);
1474*593dc095SDavid du Colombier 	glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
1475*593dc095SDavid du Colombier     }
1476*593dc095SDavid du Colombier     return 0;
1477*593dc095SDavid du Colombier }
1478*593dc095SDavid du Colombier 
1479*593dc095SDavid du Colombier /*
1480*593dc095SDavid du Colombier  * Create or find a font resource object for a text.
1481*593dc095SDavid du Colombier  */
1482*593dc095SDavid du Colombier int
pdf_obtain_font_resource(pdf_text_enum_t * penum,const gs_string * pstr,pdf_font_resource_t ** ppdfont)1483*593dc095SDavid du Colombier pdf_obtain_font_resource(pdf_text_enum_t *penum,
1484*593dc095SDavid du Colombier 	    const gs_string *pstr, pdf_font_resource_t **ppdfont)
1485*593dc095SDavid du Colombier {
1486*593dc095SDavid du Colombier     gx_device_pdf *pdev = (gx_device_pdf *)penum->dev;
1487*593dc095SDavid du Colombier     gs_font *font = (gs_font *)penum->current_font;
1488*593dc095SDavid du Colombier     byte *glyph_usage = 0;
1489*593dc095SDavid du Colombier     double *real_widths;
1490*593dc095SDavid du Colombier     int char_cache_size, width_cache_size;
1491*593dc095SDavid du Colombier     int code;
1492*593dc095SDavid du Colombier 
1493*593dc095SDavid du Colombier     if (font->FontType == ft_composite) {
1494*593dc095SDavid du Colombier 	/* Must not happen, because we always split composite fonts into descendents. */
1495*593dc095SDavid du Colombier 	return_error(gs_error_unregistered);
1496*593dc095SDavid du Colombier     }
1497*593dc095SDavid du Colombier     code = pdf_attached_font_resource(pdev, font, ppdfont,
1498*593dc095SDavid du Colombier 			       &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1499*593dc095SDavid du Colombier     /* *ppdfont is NULL if no resource attached. */
1500*593dc095SDavid du Colombier     if (code < 0)
1501*593dc095SDavid du Colombier 	return code;
1502*593dc095SDavid du Colombier     if (penum->cgp == NULL) {
1503*593dc095SDavid du Colombier 	code = pdf_alloc_text_glyphs_table(pdev, penum, pstr);
1504*593dc095SDavid du Colombier 	if (code < 0)
1505*593dc095SDavid du Colombier 	    return code;
1506*593dc095SDavid du Colombier 	code = pdf_make_text_glyphs_table(penum, pstr,
1507*593dc095SDavid du Colombier 			    glyph_usage, char_cache_size);
1508*593dc095SDavid du Colombier 	if (code < 0)
1509*593dc095SDavid du Colombier 	    return code;
1510*593dc095SDavid du Colombier     }
1511*593dc095SDavid du Colombier     code = pdf_obtain_font_resource_encoded(pdev, font, ppdfont, penum->cgp);
1512*593dc095SDavid du Colombier     if (code < 0)
1513*593dc095SDavid du Colombier 	return code;
1514*593dc095SDavid du Colombier     code = pdf_attached_font_resource(pdev, font, ppdfont,
1515*593dc095SDavid du Colombier 			       &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1516*593dc095SDavid du Colombier     if (code < 0)
1517*593dc095SDavid du Colombier 	return code;
1518*593dc095SDavid du Colombier     return pdf_mark_text_glyphs((const gs_text_enum_t *)penum, pstr, glyph_usage, char_cache_size);
1519*593dc095SDavid du Colombier }
1520*593dc095SDavid du Colombier 
1521*593dc095SDavid du Colombier /*
1522*593dc095SDavid du Colombier  * Create or find a font resource object for a glyphshow text.
1523*593dc095SDavid du Colombier  */
1524*593dc095SDavid du Colombier int
pdf_obtain_font_resource_unencoded(pdf_text_enum_t * penum,const gs_string * pstr,pdf_font_resource_t ** ppdfont,const gs_glyph * gdata)1525*593dc095SDavid du Colombier pdf_obtain_font_resource_unencoded(pdf_text_enum_t *penum,
1526*593dc095SDavid du Colombier 	    const gs_string *pstr, pdf_font_resource_t **ppdfont, const gs_glyph *gdata)
1527*593dc095SDavid du Colombier {
1528*593dc095SDavid du Colombier     gx_device_pdf *pdev = (gx_device_pdf *)penum->dev;
1529*593dc095SDavid du Colombier     gs_font *font = (gs_font *)penum->current_font;
1530*593dc095SDavid du Colombier     byte *glyph_usage = 0;
1531*593dc095SDavid du Colombier     double *real_widths = 0;
1532*593dc095SDavid du Colombier     int char_cache_size = 0, width_cache_size = 0;
1533*593dc095SDavid du Colombier     int code, ps_encoding_index;
1534*593dc095SDavid du Colombier 
1535*593dc095SDavid du Colombier     if (font->FontType == ft_composite) {
1536*593dc095SDavid du Colombier 	/* Must not happen, because we always split composite fonts into descendents. */
1537*593dc095SDavid du Colombier 	return_error(gs_error_unregistered);
1538*593dc095SDavid du Colombier     }
1539*593dc095SDavid du Colombier     code = pdf_attached_font_resource(pdev, font, ppdfont,
1540*593dc095SDavid du Colombier 			       &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1541*593dc095SDavid du Colombier     if (code < 0)
1542*593dc095SDavid du Colombier 	return code;
1543*593dc095SDavid du Colombier     /* *ppdfont is NULL if no resource attached. */
1544*593dc095SDavid du Colombier     if (penum->cgp == NULL) {
1545*593dc095SDavid du Colombier 	code = pdf_alloc_text_glyphs_table(pdev, penum, pstr);
1546*593dc095SDavid du Colombier 	if (code < 0)
1547*593dc095SDavid du Colombier 	    return code;
1548*593dc095SDavid du Colombier 	code = pdf_make_text_glyphs_table_unencoded(penum->cgp, font, pstr, gdata,
1549*593dc095SDavid du Colombier 			    &ps_encoding_index);
1550*593dc095SDavid du Colombier 	if (code < 0)
1551*593dc095SDavid du Colombier 	    return code;
1552*593dc095SDavid du Colombier     }
1553*593dc095SDavid du Colombier     code = pdf_obtain_font_resource_encoded(pdev, font, ppdfont, penum->cgp);
1554*593dc095SDavid du Colombier     if (code < 0)
1555*593dc095SDavid du Colombier 	return code;
1556*593dc095SDavid du Colombier     code = pdf_attached_font_resource(pdev, font, ppdfont,
1557*593dc095SDavid du Colombier 			       &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1558*593dc095SDavid du Colombier     if (code < 0)
1559*593dc095SDavid du Colombier 	return code;
1560*593dc095SDavid du Colombier     return pdf_mark_text_glyphs_unencoded((const gs_text_enum_t *)penum,
1561*593dc095SDavid du Colombier 		    pstr, glyph_usage, char_cache_size);
1562*593dc095SDavid du Colombier }
1563*593dc095SDavid du Colombier 
1564*593dc095SDavid du Colombier private inline bool
strings_equal(const gs_const_string * s1,const gs_const_string * s2)1565*593dc095SDavid du Colombier strings_equal(const gs_const_string *s1, const gs_const_string *s2)
1566*593dc095SDavid du Colombier {
1567*593dc095SDavid du Colombier     return s1->size == s2->size &&
1568*593dc095SDavid du Colombier 	    !memcmp(s1->data, s2->data, s1->size);
1569*593dc095SDavid du Colombier }
1570*593dc095SDavid du Colombier 
1571*593dc095SDavid du Colombier /*
1572*593dc095SDavid du Colombier  * Create or find a parent Type 0 font resource object for a CID font resource.
1573*593dc095SDavid du Colombier  */
1574*593dc095SDavid du Colombier int
pdf_obtain_parent_type0_font_resource(gx_device_pdf * pdev,pdf_font_resource_t * pdsubf,const gs_const_string * CMapName,pdf_font_resource_t ** pdfont)1575*593dc095SDavid du Colombier pdf_obtain_parent_type0_font_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdsubf,
1576*593dc095SDavid du Colombier 		const gs_const_string *CMapName, pdf_font_resource_t **pdfont)
1577*593dc095SDavid du Colombier {
1578*593dc095SDavid du Colombier     if (pdsubf->u.cidfont.parent != 0 &&
1579*593dc095SDavid du Colombier 	    strings_equal(CMapName, &pdsubf->u.cidfont.parent->u.type0.CMapName))
1580*593dc095SDavid du Colombier 	*pdfont = pdsubf->u.cidfont.parent;
1581*593dc095SDavid du Colombier     else {
1582*593dc095SDavid du Colombier 	/*
1583*593dc095SDavid du Colombier 	 * PDF spec 1.4 section 5.6 "Composite Fonts" says :
1584*593dc095SDavid du Colombier 	 *
1585*593dc095SDavid du Colombier 	 * PDF 1.2 introduces a general architecture for composite fonts that theoretically
1586*593dc095SDavid du Colombier 	 * allows a Type 0 font to have multiple descendants,which might themselves be
1587*593dc095SDavid du Colombier 	 * Type 0 fonts.However,in versions up to and including PDF 1.4,only a single
1588*593dc095SDavid du Colombier 	 * descendant is allowed,which must be a CIDFont (not a font).This restriction
1589*593dc095SDavid du Colombier 	 * may be relaxed in a future PDF version.
1590*593dc095SDavid du Colombier 	 */
1591*593dc095SDavid du Colombier 
1592*593dc095SDavid du Colombier 	if (pdsubf->u.cidfont.parent == NULL ||
1593*593dc095SDavid du Colombier 		pdf_find_type0_font_resource(pdev, pdsubf, CMapName, pdfont) <= 0) {
1594*593dc095SDavid du Colombier 	    int code = pdf_font_type0_alloc(pdev, pdfont, gs_no_id, pdsubf, CMapName);
1595*593dc095SDavid du Colombier 
1596*593dc095SDavid du Colombier 	    if (code < 0)
1597*593dc095SDavid du Colombier 		return code;
1598*593dc095SDavid du Colombier 	}
1599*593dc095SDavid du Colombier 	pdsubf->u.cidfont.parent = *pdfont;
1600*593dc095SDavid du Colombier     }
1601*593dc095SDavid du Colombier     return 0;
1602*593dc095SDavid du Colombier }
1603*593dc095SDavid du Colombier 
1604*593dc095SDavid du Colombier /*
1605*593dc095SDavid du Colombier  * Compute the cached values in the text processing state from the text
1606*593dc095SDavid du Colombier  * parameters, current_font, and pis->ctm.  Return either an error code (<
1607*593dc095SDavid du Colombier  * 0) or a mask of operation attributes that the caller must emulate.
1608*593dc095SDavid du Colombier  * Currently the only such attributes are TEXT_ADD_TO_ALL_WIDTHS and
1609*593dc095SDavid du Colombier  * TEXT_ADD_TO_SPACE_WIDTH.  Note that this procedure fills in all the
1610*593dc095SDavid du Colombier  * values in ppts->values, not just the ones that need to be set now.
1611*593dc095SDavid du Colombier  */
1612*593dc095SDavid du Colombier private int
transform_delta_inverse(const gs_point * pdelta,const gs_matrix * pmat,gs_point * ppt)1613*593dc095SDavid du Colombier transform_delta_inverse(const gs_point *pdelta, const gs_matrix *pmat,
1614*593dc095SDavid du Colombier 			gs_point *ppt)
1615*593dc095SDavid du Colombier {
1616*593dc095SDavid du Colombier     int code = gs_distance_transform_inverse(pdelta->x, pdelta->y, pmat, ppt);
1617*593dc095SDavid du Colombier     gs_point delta;
1618*593dc095SDavid du Colombier 
1619*593dc095SDavid du Colombier     if (code < 0)
1620*593dc095SDavid du Colombier 	return code;
1621*593dc095SDavid du Colombier     if (ppt->y == 0)
1622*593dc095SDavid du Colombier 	return 0;
1623*593dc095SDavid du Colombier     /* Check for numerical fuzz. */
1624*593dc095SDavid du Colombier     code = gs_distance_transform(ppt->x, 0.0, pmat, &delta);
1625*593dc095SDavid du Colombier     if (code < 0)
1626*593dc095SDavid du Colombier 	return 0;		/* punt */
1627*593dc095SDavid du Colombier     if (fabs(delta.x - pdelta->x) < 0.01 && fabs(delta.y - pdelta->y) < 0.01) {
1628*593dc095SDavid du Colombier 	/* Close enough to y == 0: device space error < 0.01 pixel. */
1629*593dc095SDavid du Colombier 	ppt->y = 0;
1630*593dc095SDavid du Colombier     }
1631*593dc095SDavid du Colombier     return 0;
1632*593dc095SDavid du Colombier }
1633*593dc095SDavid du Colombier 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)1634*593dc095SDavid du Colombier pdf_update_text_state(pdf_text_process_state_t *ppts,
1635*593dc095SDavid du Colombier 		      const pdf_text_enum_t *penum,
1636*593dc095SDavid du Colombier 		      pdf_font_resource_t *pdfont, const gs_matrix *pfmat)
1637*593dc095SDavid du Colombier {
1638*593dc095SDavid du Colombier     gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev;
1639*593dc095SDavid du Colombier     gs_font *font = penum->current_font;
1640*593dc095SDavid du Colombier     gs_fixed_point cpt;
1641*593dc095SDavid du Colombier     gs_matrix orig_matrix, smat, tmat;
1642*593dc095SDavid du Colombier     double
1643*593dc095SDavid du Colombier 	sx = pdev->HWResolution[0] / 72.0,
1644*593dc095SDavid du Colombier 	sy = pdev->HWResolution[1] / 72.0;
1645*593dc095SDavid du Colombier     float size;
1646*593dc095SDavid du Colombier     float c_s = 0, w_s = 0;
1647*593dc095SDavid du Colombier     int mask = 0;
1648*593dc095SDavid du Colombier     int code = gx_path_current_point(penum->path, &cpt);
1649*593dc095SDavid du Colombier 
1650*593dc095SDavid du Colombier     if (code < 0)
1651*593dc095SDavid du Colombier 	return code;
1652*593dc095SDavid du Colombier 
1653*593dc095SDavid du Colombier     /* Get the original matrix of the base font. */
1654*593dc095SDavid du Colombier 
1655*593dc095SDavid du Colombier     {
1656*593dc095SDavid du Colombier 	gs_font_base *cfont = pdf_font_resource_font(pdfont, false);
1657*593dc095SDavid du Colombier 
1658*593dc095SDavid du Colombier 	if (pdfont->FontType == ft_user_defined)
1659*593dc095SDavid du Colombier 	    orig_matrix = pdfont->u.simple.s.type3.FontMatrix;
1660*593dc095SDavid du Colombier 	else if (cfont != 0) {
1661*593dc095SDavid du Colombier 	    /*
1662*593dc095SDavid du Colombier 	     * The text matrix to be computed relatively to the
1663*593dc095SDavid du Colombier 	     * embedded font matrix.
1664*593dc095SDavid du Colombier 	     */
1665*593dc095SDavid du Colombier 	    orig_matrix = cfont->FontMatrix;
1666*593dc095SDavid du Colombier 	} else {
1667*593dc095SDavid du Colombier 	    /*
1668*593dc095SDavid du Colombier 	     * We don't embed the font.
1669*593dc095SDavid du Colombier 	     * The text matrix to be computed relatively to
1670*593dc095SDavid du Colombier 	     * standard font matrix.
1671*593dc095SDavid du Colombier 	     */
1672*593dc095SDavid du Colombier 	    pdf_font_orig_matrix(font, &orig_matrix);
1673*593dc095SDavid du Colombier 	}
1674*593dc095SDavid du Colombier     }
1675*593dc095SDavid du Colombier 
1676*593dc095SDavid du Colombier     /* Compute the scaling matrix and combined matrix. */
1677*593dc095SDavid du Colombier 
1678*593dc095SDavid du Colombier     gs_matrix_invert(&orig_matrix, &smat);
1679*593dc095SDavid du Colombier     gs_matrix_multiply(&smat, pfmat, &smat);
1680*593dc095SDavid du Colombier     tmat = ctm_only(penum->pis);
1681*593dc095SDavid du Colombier     tmat.tx = tmat.ty = 0;
1682*593dc095SDavid du Colombier     gs_matrix_multiply(&smat, &tmat, &tmat);
1683*593dc095SDavid du Colombier 
1684*593dc095SDavid du Colombier     /* Try to find a reasonable size value.  This isn't necessary, */
1685*593dc095SDavid du Colombier     /* but it's worth a little effort. */
1686*593dc095SDavid du Colombier 
1687*593dc095SDavid du Colombier     size = hypot(tmat.yx, tmat.yy) / sy;
1688*593dc095SDavid du Colombier     if (size < 0.01)
1689*593dc095SDavid du Colombier 	size = hypot(tmat.xx, tmat.xy) / sx;
1690*593dc095SDavid du Colombier     if (size < 0.01)
1691*593dc095SDavid du Colombier 	size = 1;
1692*593dc095SDavid du Colombier 
1693*593dc095SDavid du Colombier     /* Check for spacing parameters we can handle, and transform them. */
1694*593dc095SDavid du Colombier 
1695*593dc095SDavid du Colombier     if (penum->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
1696*593dc095SDavid du Colombier 	if (penum->current_font->WMode == 0) {
1697*593dc095SDavid du Colombier 	    gs_point pt;
1698*593dc095SDavid du Colombier 
1699*593dc095SDavid du Colombier 	    code = transform_delta_inverse(&penum->text.delta_all, &smat, &pt);
1700*593dc095SDavid du Colombier 	    if (code >= 0 && pt.y == 0)
1701*593dc095SDavid du Colombier 		c_s = pt.x * size;
1702*593dc095SDavid du Colombier 	    else
1703*593dc095SDavid du Colombier 		mask |= TEXT_ADD_TO_ALL_WIDTHS;
1704*593dc095SDavid du Colombier 	}
1705*593dc095SDavid du Colombier 	else
1706*593dc095SDavid du Colombier 	    mask |= TEXT_ADD_TO_ALL_WIDTHS;
1707*593dc095SDavid du Colombier     }
1708*593dc095SDavid du Colombier 
1709*593dc095SDavid du Colombier     if (penum->text.operation & TEXT_ADD_TO_SPACE_WIDTH) {
1710*593dc095SDavid du Colombier 	gs_point pt;
1711*593dc095SDavid du Colombier 
1712*593dc095SDavid du Colombier 	code = transform_delta_inverse(&penum->text.delta_space, &smat, &pt);
1713*593dc095SDavid du Colombier 	if (code >= 0 && pt.y == 0 && penum->text.space.s_char == 32)
1714*593dc095SDavid du Colombier 	    w_s = pt.x * size;
1715*593dc095SDavid du Colombier 	else
1716*593dc095SDavid du Colombier 	    mask |= TEXT_ADD_TO_SPACE_WIDTH;
1717*593dc095SDavid du Colombier     }
1718*593dc095SDavid du Colombier     /* Store the updated values. */
1719*593dc095SDavid du Colombier 
1720*593dc095SDavid du Colombier     tmat.xx /= size;
1721*593dc095SDavid du Colombier     tmat.xy /= size;
1722*593dc095SDavid du Colombier     tmat.yx /= size;
1723*593dc095SDavid du Colombier     tmat.yy /= size;
1724*593dc095SDavid du Colombier     tmat.tx += fixed2float(cpt.x);
1725*593dc095SDavid du Colombier     tmat.ty += fixed2float(cpt.y);
1726*593dc095SDavid du Colombier 
1727*593dc095SDavid du Colombier     ppts->values.character_spacing = c_s;
1728*593dc095SDavid du Colombier     ppts->values.pdfont = pdfont;
1729*593dc095SDavid du Colombier     ppts->values.size = size;
1730*593dc095SDavid du Colombier     ppts->values.matrix = tmat;
1731*593dc095SDavid du Colombier     ppts->values.render_mode = (penum->pis->text_rendering_mode == 3 ? 3 :
1732*593dc095SDavid du Colombier 				font->PaintType == 0 ? 0 : 1);
1733*593dc095SDavid du Colombier     ppts->values.word_spacing = w_s;
1734*593dc095SDavid du Colombier     ppts->font = font;
1735*593dc095SDavid du Colombier 
1736*593dc095SDavid du Colombier     code = pdf_set_text_process_state(pdev, (const gs_text_enum_t *)penum,
1737*593dc095SDavid du Colombier 				      ppts);
1738*593dc095SDavid du Colombier     return (code < 0 ? code : mask);
1739*593dc095SDavid du Colombier }
1740*593dc095SDavid du Colombier 
1741*593dc095SDavid du Colombier /*
1742*593dc095SDavid du Colombier  * Set up commands to make the output state match the processing state.
1743*593dc095SDavid du Colombier  * General graphics state commands are written now; text state commands
1744*593dc095SDavid du Colombier  * are written later.
1745*593dc095SDavid du Colombier  */
1746*593dc095SDavid du Colombier private double
font_matrix_scaling(const gs_font * font)1747*593dc095SDavid du Colombier font_matrix_scaling(const gs_font *font)
1748*593dc095SDavid du Colombier {
1749*593dc095SDavid du Colombier     return fabs((font->FontMatrix.yy != 0 ? font->FontMatrix.yy :
1750*593dc095SDavid du Colombier 		 font->FontMatrix.yx));
1751*593dc095SDavid du Colombier }
1752*593dc095SDavid du Colombier int
pdf_set_text_process_state(gx_device_pdf * pdev,const gs_text_enum_t * pte,pdf_text_process_state_t * ppts)1753*593dc095SDavid du Colombier pdf_set_text_process_state(gx_device_pdf *pdev,
1754*593dc095SDavid du Colombier 			   const gs_text_enum_t *pte,	/* for pdcolor, pis */
1755*593dc095SDavid du Colombier 			   pdf_text_process_state_t *ppts)
1756*593dc095SDavid du Colombier {
1757*593dc095SDavid du Colombier     /*
1758*593dc095SDavid du Colombier      * Setting the stroke parameters may exit text mode, causing the
1759*593dc095SDavid du Colombier      * settings of the text parameters to be lost.  Therefore, we set the
1760*593dc095SDavid du Colombier      * stroke parameters first.
1761*593dc095SDavid du Colombier      */
1762*593dc095SDavid du Colombier     if (pdf_render_mode_uses_stroke(pdev, &ppts->values)) {
1763*593dc095SDavid du Colombier 	/* Write all the parameters for stroking. */
1764*593dc095SDavid du Colombier 	gs_imager_state *pis = pte->pis;
1765*593dc095SDavid du Colombier 	float save_width = pis->line_params.half_width;
1766*593dc095SDavid du Colombier 	const gs_font *font = ppts->font;
1767*593dc095SDavid du Colombier 	double scaled_width = font->StrokeWidth;
1768*593dc095SDavid du Colombier 	int code;
1769*593dc095SDavid du Colombier 
1770*593dc095SDavid du Colombier 	/* Note that we compute pis->line_params.half_width in device space,
1771*593dc095SDavid du Colombier 	 * even though it logically represents a value in user space.
1772*593dc095SDavid du Colombier 	 * The 'scale' value compensates for this.
1773*593dc095SDavid du Colombier 	 */
1774*593dc095SDavid du Colombier 	scaled_width *= font_matrix_scaling(font);
1775*593dc095SDavid du Colombier 	scaled_width *= min(hypot(pte->pis->ctm.xx, pte->pis->ctm.yx) /
1776*593dc095SDavid du Colombier                                 pdev->HWResolution[0] * pdev->HWResolution[1],
1777*593dc095SDavid du Colombier                             hypot(pte->pis->ctm.xy, pte->pis->ctm.yy));
1778*593dc095SDavid du Colombier 	pis->line_params.half_width = scaled_width / 2;
1779*593dc095SDavid du Colombier 	code = pdf_prepare_stroke(pdev, pis);
1780*593dc095SDavid du Colombier 	if (code >= 0) {
1781*593dc095SDavid du Colombier 	    /*
1782*593dc095SDavid du Colombier 	     * See stream_to_text in gdevpdfu.c re the computation of
1783*593dc095SDavid du Colombier 	     * the scaling value.
1784*593dc095SDavid du Colombier 	     */
1785*593dc095SDavid du Colombier 	    double scale = 72.0 / pdev->HWResolution[1];
1786*593dc095SDavid du Colombier 
1787*593dc095SDavid du Colombier 	    code = gdev_vector_prepare_stroke((gx_device_vector *)pdev,
1788*593dc095SDavid du Colombier 					      pis, NULL, NULL, scale);
1789*593dc095SDavid du Colombier 	}
1790*593dc095SDavid du Colombier 	pis->line_params.half_width = save_width;
1791*593dc095SDavid du Colombier 	if (code < 0)
1792*593dc095SDavid du Colombier 	    return code;
1793*593dc095SDavid du Colombier     }
1794*593dc095SDavid du Colombier 
1795*593dc095SDavid du Colombier     /* Now set all the other parameters. */
1796*593dc095SDavid du Colombier 
1797*593dc095SDavid du Colombier     return pdf_set_text_state_values(pdev, &ppts->values);
1798*593dc095SDavid du Colombier }
1799*593dc095SDavid du Colombier 
1800*593dc095SDavid du Colombier private int
store_glyph_width(pdf_glyph_width_t * pwidth,int wmode,double scale,const gs_glyph_info_t * pinfo)1801*593dc095SDavid du Colombier store_glyph_width(pdf_glyph_width_t *pwidth, int wmode, double scale,
1802*593dc095SDavid du Colombier 		  const gs_glyph_info_t *pinfo)
1803*593dc095SDavid du Colombier {
1804*593dc095SDavid du Colombier     double w, v;
1805*593dc095SDavid du Colombier 
1806*593dc095SDavid du Colombier     pwidth->xy.x = pinfo->width[wmode].x * scale;
1807*593dc095SDavid du Colombier     pwidth->xy.y = pinfo->width[wmode].y * scale;
1808*593dc095SDavid du Colombier     if (wmode)
1809*593dc095SDavid du Colombier 	w = pwidth->xy.y, v = pwidth->xy.x;
1810*593dc095SDavid du Colombier     else
1811*593dc095SDavid du Colombier 	w = pwidth->xy.x, v = pwidth->xy.y;
1812*593dc095SDavid du Colombier     if (v != 0)
1813*593dc095SDavid du Colombier 	return 1;
1814*593dc095SDavid du Colombier     pwidth->w = w;
1815*593dc095SDavid du Colombier     pwidth->v.x = pinfo->v.x * scale;
1816*593dc095SDavid du Colombier     pwidth->v.y = pinfo->v.y * scale;
1817*593dc095SDavid du Colombier     return 0;
1818*593dc095SDavid du Colombier }
1819*593dc095SDavid du Colombier 
1820*593dc095SDavid du Colombier private int
get_missing_width(gs_font_base * cfont,int wmode,double scale_c,pdf_glyph_widths_t * pwidths)1821*593dc095SDavid du Colombier get_missing_width(gs_font_base *cfont, int wmode, double scale_c,
1822*593dc095SDavid du Colombier 		    pdf_glyph_widths_t *pwidths)
1823*593dc095SDavid du Colombier {
1824*593dc095SDavid du Colombier     gs_font_info_t finfo;
1825*593dc095SDavid du Colombier     int code;
1826*593dc095SDavid du Colombier 
1827*593dc095SDavid du Colombier     code = cfont->procs.font_info((gs_font *)cfont, NULL,
1828*593dc095SDavid du Colombier 				  FONT_INFO_MISSING_WIDTH, &finfo);
1829*593dc095SDavid du Colombier     if (code < 0)
1830*593dc095SDavid du Colombier 	return code;
1831*593dc095SDavid du Colombier     if (wmode) {
1832*593dc095SDavid du Colombier 	pwidths->Width.xy.x = pwidths->real_width.xy.x = 0;
1833*593dc095SDavid du Colombier 	pwidths->Width.xy.y = pwidths->real_width.xy.y =
1834*593dc095SDavid du Colombier 		- finfo.MissingWidth * scale_c;
1835*593dc095SDavid du Colombier 	pwidths->Width.w = pwidths->real_width.w =
1836*593dc095SDavid du Colombier 		pwidths->Width.xy.y;
1837*593dc095SDavid du Colombier 	pwidths->Width.v.x = - pwidths->Width.xy.y / 2;
1838*593dc095SDavid du Colombier 	pwidths->Width.v.y = - pwidths->Width.xy.y;
1839*593dc095SDavid du Colombier     } else {
1840*593dc095SDavid du Colombier 	pwidths->Width.xy.x = pwidths->real_width.xy.x =
1841*593dc095SDavid du Colombier 		finfo.MissingWidth * scale_c;
1842*593dc095SDavid du Colombier 	pwidths->Width.w = pwidths->real_width.w =
1843*593dc095SDavid du Colombier 		pwidths->Width.xy.x;
1844*593dc095SDavid du Colombier 	pwidths->Width.xy.y = pwidths->real_width.xy.y = 0;
1845*593dc095SDavid du Colombier 	pwidths->Width.v.x = pwidths->Width.v.y = 0;
1846*593dc095SDavid du Colombier     }
1847*593dc095SDavid du Colombier     /*
1848*593dc095SDavid du Colombier      * Don't mark the width as known, just in case this is an
1849*593dc095SDavid du Colombier      * incrementally defined font.
1850*593dc095SDavid du Colombier      */
1851*593dc095SDavid du Colombier     return 1;
1852*593dc095SDavid du Colombier }
1853*593dc095SDavid du Colombier 
1854*593dc095SDavid du Colombier 
1855*593dc095SDavid du Colombier /*
1856*593dc095SDavid du Colombier  * Get the widths (unmodified from the copied font,
1857*593dc095SDavid du Colombier  * and possibly modified from the original font) of a given glyph.
1858*593dc095SDavid du Colombier  * Return 1 if the width was defaulted to MissingWidth.
1859*593dc095SDavid du Colombier  * Return TEXT_PROCESS_CDEVPROC if a CDevProc callout is needed.
1860*593dc095SDavid du Colombier  * cdevproc_result != NULL if we restart after a CDevProc callout.
1861*593dc095SDavid du Colombier  */
1862*593dc095SDavid du Colombier int
pdf_glyph_widths(pdf_font_resource_t * pdfont,int wmode,gs_glyph glyph,gs_font * orig_font,pdf_glyph_widths_t * pwidths,const double cdevproc_result[10])1863*593dc095SDavid du Colombier pdf_glyph_widths(pdf_font_resource_t *pdfont, int wmode, gs_glyph glyph,
1864*593dc095SDavid du Colombier 		 gs_font *orig_font, pdf_glyph_widths_t *pwidths,
1865*593dc095SDavid du Colombier 		 const double cdevproc_result[10])
1866*593dc095SDavid du Colombier {
1867*593dc095SDavid du Colombier     gs_font_base *cfont = pdf_font_resource_font(pdfont, false);
1868*593dc095SDavid du Colombier     gs_font *ofont = orig_font;
1869*593dc095SDavid du Colombier     gs_glyph_info_t info;
1870*593dc095SDavid du Colombier     /*
1871*593dc095SDavid du Colombier      * orig_scale is 1.0 for TrueType, 0.001 or 1.0/2048 for Type 1.
1872*593dc095SDavid du Colombier      */
1873*593dc095SDavid du Colombier     double sxc, sxo;
1874*593dc095SDavid du Colombier     double scale_c, scale_o;
1875*593dc095SDavid du Colombier     int code, rcode = 0;
1876*593dc095SDavid du Colombier     gs_point v;
1877*593dc095SDavid du Colombier     int allow_cdevproc_callout = (orig_font->FontType == ft_CID_TrueType
1878*593dc095SDavid du Colombier 		|| orig_font->FontType == ft_CID_encrypted
1879*593dc095SDavid du Colombier 		? GLYPH_INFO_CDEVPROC : 0); /* fixme : allow more font types. */
1880*593dc095SDavid du Colombier 
1881*593dc095SDavid du Colombier     if (ofont->FontType == ft_composite)
1882*593dc095SDavid du Colombier 	return_error(gs_error_unregistered); /* Must not happen. */
1883*593dc095SDavid du Colombier     code = font_orig_scale((const gs_font *)cfont, &sxc);
1884*593dc095SDavid du Colombier     if (code < 0)
1885*593dc095SDavid du Colombier 	return code;
1886*593dc095SDavid du Colombier     code = font_orig_scale(ofont, &sxo);
1887*593dc095SDavid du Colombier     if (code < 0)
1888*593dc095SDavid du Colombier 	return code;
1889*593dc095SDavid du Colombier     scale_c = sxc * 1000.0;
1890*593dc095SDavid du Colombier     scale_o = sxo * 1000.0;
1891*593dc095SDavid du Colombier     pwidths->Width.v.x = pwidths->Width.v.y = 0;
1892*593dc095SDavid du Colombier     pwidths->real_width.v.x = pwidths->real_width.v.y = 0;
1893*593dc095SDavid du Colombier     pwidths->replaced_v = false;
1894*593dc095SDavid du Colombier     if (glyph == GS_NO_GLYPH)
1895*593dc095SDavid du Colombier 	return get_missing_width(cfont, wmode, scale_c, pwidths);
1896*593dc095SDavid du Colombier     code = cfont->procs.glyph_info((gs_font *)cfont, glyph, NULL,
1897*593dc095SDavid du Colombier 				    GLYPH_INFO_WIDTH0 |
1898*593dc095SDavid du Colombier 				    (GLYPH_INFO_WIDTH0 << wmode) |
1899*593dc095SDavid du Colombier 				    GLYPH_INFO_OUTLINE_WIDTHS |
1900*593dc095SDavid du Colombier 				    (GLYPH_INFO_VVECTOR0 << wmode),
1901*593dc095SDavid du Colombier 				    &info);
1902*593dc095SDavid du Colombier     /* For CID fonts the PDF spec requires the x-component of v-vector
1903*593dc095SDavid du Colombier        to be equal to half glyph width, and AR5 takes it from W, DW.
1904*593dc095SDavid du Colombier        So make a compatibe data here.
1905*593dc095SDavid du Colombier      */
1906*593dc095SDavid du Colombier     if (code == gs_error_undefined || !(info.members & (GLYPH_INFO_WIDTH0 << wmode))) {
1907*593dc095SDavid du Colombier 	code = get_missing_width(cfont, wmode, scale_c, pwidths);
1908*593dc095SDavid du Colombier 	if (code < 0)
1909*593dc095SDavid du Colombier 	    v.y = 0;
1910*593dc095SDavid du Colombier 	else
1911*593dc095SDavid du Colombier 	    v.y = pwidths->Width.v.y;
1912*593dc095SDavid du Colombier 	if (wmode && pdf_is_CID_font(ofont)) {
1913*593dc095SDavid du Colombier 	    pdf_glyph_widths_t widths1;
1914*593dc095SDavid du Colombier 
1915*593dc095SDavid du Colombier 	    if (get_missing_width(cfont, 0, scale_c, &widths1) < 0)
1916*593dc095SDavid du Colombier 		v.x = 0;
1917*593dc095SDavid du Colombier 	    else
1918*593dc095SDavid du Colombier 		v.x = widths1.Width.w / 2;
1919*593dc095SDavid du Colombier 	} else
1920*593dc095SDavid du Colombier 	    v.x = pwidths->Width.v.x;
1921*593dc095SDavid du Colombier     } else if (code < 0)
1922*593dc095SDavid du Colombier 	return code;
1923*593dc095SDavid du Colombier     else {
1924*593dc095SDavid du Colombier 	code = store_glyph_width(&pwidths->Width, wmode, scale_c, &info);
1925*593dc095SDavid du Colombier 	if (code < 0)
1926*593dc095SDavid du Colombier 	    return code;
1927*593dc095SDavid du Colombier 	rcode |= code;
1928*593dc095SDavid du Colombier 	if (info.members & (GLYPH_INFO_VVECTOR0 << wmode)) {
1929*593dc095SDavid du Colombier 	    v.y = info.v.y * scale_c;
1930*593dc095SDavid du Colombier 	} else
1931*593dc095SDavid du Colombier 	    v.y = 0;
1932*593dc095SDavid du Colombier 	if (wmode && pdf_is_CID_font(ofont)) {
1933*593dc095SDavid du Colombier 	    if (info.members & (GLYPH_INFO_WIDTH0 << wmode)) {
1934*593dc095SDavid du Colombier 		v.x = info.width[0].x * scale_c / 2;
1935*593dc095SDavid du Colombier 	    } else {
1936*593dc095SDavid du Colombier 		pdf_glyph_widths_t widths1;
1937*593dc095SDavid du Colombier 
1938*593dc095SDavid du Colombier 		if (get_missing_width(cfont, 0, scale_c, &widths1) < 0)
1939*593dc095SDavid du Colombier 		    v.x = 0;
1940*593dc095SDavid du Colombier 		else
1941*593dc095SDavid du Colombier 		    v.x = widths1.Width.w / 2;
1942*593dc095SDavid du Colombier 	    }
1943*593dc095SDavid du Colombier 	} else {
1944*593dc095SDavid du Colombier 	    if (info.members  & (GLYPH_INFO_VVECTOR0 << wmode)) {
1945*593dc095SDavid du Colombier 		v.x = info.v.x * scale_c;
1946*593dc095SDavid du Colombier 	    } else
1947*593dc095SDavid du Colombier 		v.x = 0;
1948*593dc095SDavid du Colombier 	}
1949*593dc095SDavid du Colombier     }
1950*593dc095SDavid du Colombier     pwidths->Width.v = v;
1951*593dc095SDavid du Colombier #if 0
1952*593dc095SDavid du Colombier     if (code > 0)
1953*593dc095SDavid du Colombier 	pwidths->Width.xy.x = pwidths->Width.xy.y = pwidths->Width.w = 0;
1954*593dc095SDavid du Colombier #else /* Skip only if not paralel to the axis. */
1955*593dc095SDavid du Colombier     if (code > 0 && !pdf_is_CID_font(ofont))
1956*593dc095SDavid du Colombier 	pwidths->Width.xy.x = pwidths->Width.xy.y = pwidths->Width.w = 0;
1957*593dc095SDavid du Colombier #endif
1958*593dc095SDavid du Colombier     if (cdevproc_result == NULL) {
1959*593dc095SDavid du Colombier 	code = ofont->procs.glyph_info(ofont, glyph, NULL,
1960*593dc095SDavid du Colombier 					    (GLYPH_INFO_WIDTH0 << wmode) |
1961*593dc095SDavid du Colombier 					    (GLYPH_INFO_VVECTOR0 << wmode) |
1962*593dc095SDavid du Colombier 					    allow_cdevproc_callout,
1963*593dc095SDavid du Colombier 					    &info);
1964*593dc095SDavid du Colombier 	/* fixme : Move this call before cfont->procs.glyph_info. */
1965*593dc095SDavid du Colombier 	if (info.members & GLYPH_INFO_CDEVPROC) {
1966*593dc095SDavid du Colombier 	    if (allow_cdevproc_callout)
1967*593dc095SDavid du Colombier 		return TEXT_PROCESS_CDEVPROC;
1968*593dc095SDavid du Colombier 	    else
1969*593dc095SDavid du Colombier 		return_error(gs_error_rangecheck);
1970*593dc095SDavid du Colombier 	}
1971*593dc095SDavid du Colombier     } else {
1972*593dc095SDavid du Colombier 	info.width[0].x = cdevproc_result[0];
1973*593dc095SDavid du Colombier 	info.width[0].y = cdevproc_result[1];
1974*593dc095SDavid du Colombier 	info.width[1].x = cdevproc_result[6];
1975*593dc095SDavid du Colombier 	info.width[1].y = cdevproc_result[7];
1976*593dc095SDavid du Colombier 	info.v.x = (wmode ? cdevproc_result[8] : 0);
1977*593dc095SDavid du Colombier 	info.v.y = (wmode ? cdevproc_result[9] : 0);
1978*593dc095SDavid du Colombier 	info.members = (GLYPH_INFO_WIDTH0 << wmode) |
1979*593dc095SDavid du Colombier 		       (wmode ? GLYPH_INFO_VVECTOR1 : 0);
1980*593dc095SDavid du Colombier 	code = 0;
1981*593dc095SDavid du Colombier     }
1982*593dc095SDavid du Colombier     if (code == gs_error_undefined || !(info.members & (GLYPH_INFO_WIDTH0 << wmode)))
1983*593dc095SDavid du Colombier 	pwidths->real_width = pwidths->Width;
1984*593dc095SDavid du Colombier     else if (code < 0)
1985*593dc095SDavid du Colombier 	return code;
1986*593dc095SDavid du Colombier     else {
1987*593dc095SDavid du Colombier 	if ((info.members & (GLYPH_INFO_VVECTOR0 | GLYPH_INFO_VVECTOR1)) != 0)
1988*593dc095SDavid du Colombier 	    pwidths->replaced_v = true;
1989*593dc095SDavid du Colombier 	else
1990*593dc095SDavid du Colombier 	    info.v.x = info.v.y = 0;
1991*593dc095SDavid du Colombier 	code = store_glyph_width(&pwidths->real_width, wmode, scale_o, &info);
1992*593dc095SDavid du Colombier 	if (code < 0)
1993*593dc095SDavid du Colombier 	    return code;
1994*593dc095SDavid du Colombier 	rcode |= code;
1995*593dc095SDavid du Colombier 	pwidths->real_width.v.x = info.v.x * scale_o;
1996*593dc095SDavid du Colombier 	pwidths->real_width.v.y = info.v.y * scale_o;
1997*593dc095SDavid du Colombier     }
1998*593dc095SDavid du Colombier     return rcode;
1999*593dc095SDavid du Colombier }
2000*593dc095SDavid du Colombier /* ---------------- Main entry ---------------- */
2001*593dc095SDavid du Colombier 
2002*593dc095SDavid du Colombier /*
2003*593dc095SDavid du Colombier  * Fall back to the default text processing code when needed.
2004*593dc095SDavid du Colombier  */
2005*593dc095SDavid du Colombier int
pdf_default_text_begin(gs_text_enum_t * pte,const gs_text_params_t * text,gs_text_enum_t ** ppte)2006*593dc095SDavid du Colombier pdf_default_text_begin(gs_text_enum_t *pte, const gs_text_params_t *text,
2007*593dc095SDavid du Colombier 		       gs_text_enum_t **ppte)
2008*593dc095SDavid du Colombier {
2009*593dc095SDavid du Colombier     gs_text_params_t text1 = *text;
2010*593dc095SDavid du Colombier 
2011*593dc095SDavid du Colombier     if(pte->current_font->FontType == 3 && (text1.operation & TEXT_DO_NONE)) {
2012*593dc095SDavid du Colombier 	/* We need a real drawing to accumulate charproc. */
2013*593dc095SDavid du Colombier 	text1.operation &= ~TEXT_DO_NONE;
2014*593dc095SDavid du Colombier 	text1.operation |= TEXT_DO_DRAW;
2015*593dc095SDavid du Colombier     }
2016*593dc095SDavid du Colombier     return gx_default_text_begin(pte->dev, pte->pis, &text1, pte->current_font,
2017*593dc095SDavid du Colombier 				 pte->path, pte->pdcolor, pte->pcpath,
2018*593dc095SDavid du Colombier 				 pte->memory, ppte);
2019*593dc095SDavid du Colombier }
2020*593dc095SDavid du Colombier 
2021*593dc095SDavid du Colombier /*
2022*593dc095SDavid du Colombier  * Continue processing text.  This is the 'process' procedure in the text
2023*593dc095SDavid du Colombier  * enumerator.  Per the check in pdf_text_begin, we know the operation is
2024*593dc095SDavid du Colombier  * not a charpath, but it could be anything else.
2025*593dc095SDavid du Colombier  */
2026*593dc095SDavid du Colombier int
pdf_text_process(gs_text_enum_t * pte)2027*593dc095SDavid du Colombier pdf_text_process(gs_text_enum_t *pte)
2028*593dc095SDavid du Colombier {
2029*593dc095SDavid du Colombier     pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
2030*593dc095SDavid du Colombier     uint operation = pte->text.operation;
2031*593dc095SDavid du Colombier     uint size = pte->text.size - pte->index;
2032*593dc095SDavid du Colombier     gs_text_enum_t *pte_default;
2033*593dc095SDavid du Colombier     PROCESS_TEXT_PROC((*process));
2034*593dc095SDavid du Colombier     int code;
2035*593dc095SDavid du Colombier     gx_device_pdf *pdev = (gx_device_pdf *)penum->dev;
2036*593dc095SDavid du Colombier #define BUF_SIZE 100		/* arbitrary > 0 */
2037*593dc095SDavid du Colombier     /* Use a union to ensure alignment. */
2038*593dc095SDavid du Colombier     union bu_ {
2039*593dc095SDavid du Colombier 	byte bytes[BUF_SIZE];
2040*593dc095SDavid du Colombier 	gs_char chars[BUF_SIZE / sizeof(gs_char)];
2041*593dc095SDavid du Colombier 	gs_glyph glyphs[BUF_SIZE / sizeof(gs_glyph)];
2042*593dc095SDavid du Colombier     } buf;
2043*593dc095SDavid du Colombier 
2044*593dc095SDavid du Colombier     if (!penum->pte_default && !penum->charproc_accum) {
2045*593dc095SDavid du Colombier 	/* Don't need to sync before exiting charproc. */
2046*593dc095SDavid du Colombier 	code = pdf_prepare_text_drawing(pdev, pte);
2047*593dc095SDavid du Colombier 	if (code == gs_error_rangecheck) {
2048*593dc095SDavid du Colombier 	    /* Fallback to the default implermentation for handling
2049*593dc095SDavid du Colombier 	       a transparency with CompatibilityLevel<=1.3 . */
2050*593dc095SDavid du Colombier 	    goto default_impl;
2051*593dc095SDavid du Colombier 	}
2052*593dc095SDavid du Colombier 	if (penum->outer_CID != GS_NO_GLYPH) {
2053*593dc095SDavid du Colombier 	    /* Fallback to the default implermentation for handling
2054*593dc095SDavid du Colombier 	       Type 3 fonts with CIDs, because currently Type 3
2055*593dc095SDavid du Colombier 	       font resource arrays' sizes are hardcoded to 256 glyphs.
2056*593dc095SDavid du Colombier 	       A better solution would be to re-encode the CID text with
2057*593dc095SDavid du Colombier 	       Type 3 glyph variations. */
2058*593dc095SDavid du Colombier 	    goto default_impl;
2059*593dc095SDavid du Colombier 	}
2060*593dc095SDavid du Colombier 	if (code < 0)
2061*593dc095SDavid du Colombier 	    return code;
2062*593dc095SDavid du Colombier     }
2063*593dc095SDavid du Colombier     if (!penum->pte_default) {
2064*593dc095SDavid du Colombier 	pdev->charproc_just_accumulated = false;
2065*593dc095SDavid du Colombier 	if (penum->cdevproc_callout) {
2066*593dc095SDavid du Colombier 	    /* Restore after TEXT_PROCESS_CDEVPROC in scan_cmap_text. */
2067*593dc095SDavid du Colombier 	    penum->current_font = penum->orig_font;
2068*593dc095SDavid du Colombier 	}
2069*593dc095SDavid du Colombier     }
2070*593dc095SDavid du Colombier     code = -1;		/* to force default implementation */
2071*593dc095SDavid du Colombier 
2072*593dc095SDavid du Colombier     /*
2073*593dc095SDavid du Colombier      * If we fell back to the default implementation, continue using it.
2074*593dc095SDavid du Colombier      */
2075*593dc095SDavid du Colombier  top:
2076*593dc095SDavid du Colombier     pte_default = penum->pte_default;
2077*593dc095SDavid du Colombier     if (pte_default) {
2078*593dc095SDavid du Colombier 	if (penum->charproc_accum) {
2079*593dc095SDavid du Colombier 	    code = pdf_end_charproc_accum(pdev, penum->current_font, penum->cgp);
2080*593dc095SDavid du Colombier 	    if (code < 0)
2081*593dc095SDavid du Colombier 		return code;
2082*593dc095SDavid du Colombier 	    penum->charproc_accum = false;
2083*593dc095SDavid du Colombier 	    code = gx_default_text_restore_state(pte_default);
2084*593dc095SDavid du Colombier 	    if (code < 0)
2085*593dc095SDavid du Colombier 		return code;
2086*593dc095SDavid du Colombier 	    gs_text_release(pte_default, "pdf_text_process");
2087*593dc095SDavid du Colombier 	    penum->pte_default = 0;
2088*593dc095SDavid du Colombier 	    goto top;
2089*593dc095SDavid du Colombier 	}
2090*593dc095SDavid du Colombier 	pdev->pte = pte_default; /* CAUTION: See comment in gdevpdfx.h . */
2091*593dc095SDavid du Colombier 	code = gs_text_process(pte_default);
2092*593dc095SDavid du Colombier 	pdev->pte = NULL;	 /* CAUTION: See comment in gdevpdfx.h . */
2093*593dc095SDavid du Colombier 	if (pte->orig_font->FontType != ft_user_defined)
2094*593dc095SDavid du Colombier 	    gs_text_enum_copy_dynamic(pte, pte_default, true);
2095*593dc095SDavid du Colombier 	else {
2096*593dc095SDavid du Colombier 	    penum->returned.current_char = pte_default->returned.current_char;
2097*593dc095SDavid du Colombier 	    penum->returned.current_glyph = pte_default->returned.current_glyph;
2098*593dc095SDavid du Colombier 	}
2099*593dc095SDavid du Colombier 	pdev->charproc_just_accumulated = false;
2100*593dc095SDavid du Colombier 	if (code == TEXT_PROCESS_RENDER) {
2101*593dc095SDavid du Colombier 	    pdev->charproc_ctm = penum->pis->ctm;
2102*593dc095SDavid du Colombier 	    if (penum->current_font->FontType == ft_user_defined &&
2103*593dc095SDavid du Colombier 		    penum->orig_font->FontType != ft_composite &&
2104*593dc095SDavid du Colombier 		    penum->outer_CID == GS_NO_GLYPH &&
2105*593dc095SDavid du Colombier 		    !(penum->pte_default->text.operation & TEXT_DO_CHARWIDTH)) {
2106*593dc095SDavid du Colombier 		/* The condition above must be consistent with one in pdf_text_set_cache,
2107*593dc095SDavid du Colombier 		   which decides to apply pdf_set_charproc_attrs. */
2108*593dc095SDavid du Colombier 		gs_matrix m;
2109*593dc095SDavid du Colombier 
2110*593dc095SDavid du Colombier 		code = pdf_start_charproc_accum(pdev);
2111*593dc095SDavid du Colombier 		if (code < 0)
2112*593dc095SDavid du Colombier 		    return code;
2113*593dc095SDavid du Colombier 		pdf_viewer_state_from_imager_state(pdev, pte->pis, pte->pdcolor);
2114*593dc095SDavid du Colombier 		/* Set line params to unallowed values so that
2115*593dc095SDavid du Colombier 		   they'll synchronize with writing them out on the first use.
2116*593dc095SDavid du Colombier 		   Doing so because PDF viewer inherits them from the
2117*593dc095SDavid du Colombier 		   contents stream when executing the charproc,
2118*593dc095SDavid du Colombier 		   but at this moment we don't know in what contexts
2119*593dc095SDavid du Colombier 		   it will be used. */
2120*593dc095SDavid du Colombier 		pdev->state.line_params.half_width = -1;
2121*593dc095SDavid du Colombier 		pdev->state.line_params.cap = gs_cap_unknown;
2122*593dc095SDavid du Colombier 		pdev->state.line_params.join = gs_join_unknown;
2123*593dc095SDavid du Colombier 		pdev->state.line_params.miter_limit = -1;
2124*593dc095SDavid du Colombier 		pdev->state.line_params.dash.pattern_size = -1;
2125*593dc095SDavid du Colombier 		/* Must set an identity CTM for the charproc accumulation.
2126*593dc095SDavid du Colombier 		   The function show_proceed (called from gs_text_process above)
2127*593dc095SDavid du Colombier 		   executed gsave, so we are safe to change CTM now.
2128*593dc095SDavid du Colombier 		   Note that BuildChar may change CTM before calling setcachedevice. */
2129*593dc095SDavid du Colombier 		gs_make_identity(&m);
2130*593dc095SDavid du Colombier 		gs_matrix_fixed_from_matrix(&penum->pis->ctm, &m);
2131*593dc095SDavid du Colombier 		return TEXT_PROCESS_RENDER;
2132*593dc095SDavid du Colombier 	    }
2133*593dc095SDavid du Colombier 	}
2134*593dc095SDavid du Colombier 	if (code)
2135*593dc095SDavid du Colombier 	    return code;
2136*593dc095SDavid du Colombier 	gs_text_release(pte_default, "pdf_text_process");
2137*593dc095SDavid du Colombier 	penum->pte_default = 0;
2138*593dc095SDavid du Colombier 	return 0;
2139*593dc095SDavid du Colombier     }
2140*593dc095SDavid du Colombier     {
2141*593dc095SDavid du Colombier 	gs_font *font = pte->orig_font; /* Not sure. Changed for CDevProc callout. Was pte->current_font */
2142*593dc095SDavid du Colombier 
2143*593dc095SDavid du Colombier 	switch (font->FontType) {
2144*593dc095SDavid du Colombier 	case ft_CID_encrypted:
2145*593dc095SDavid du Colombier 	case ft_CID_TrueType:
2146*593dc095SDavid du Colombier 	    process = process_cid_text;
2147*593dc095SDavid du Colombier 	    break;
2148*593dc095SDavid du Colombier 	case ft_encrypted:
2149*593dc095SDavid du Colombier 	case ft_encrypted2:
2150*593dc095SDavid du Colombier 	case ft_TrueType:
2151*593dc095SDavid du Colombier 	case ft_user_defined:
2152*593dc095SDavid du Colombier 	    /* The data may be either glyphs or characters. */
2153*593dc095SDavid du Colombier 	    process = process_plain_text;
2154*593dc095SDavid du Colombier 	    break;
2155*593dc095SDavid du Colombier 	case ft_composite:
2156*593dc095SDavid du Colombier 	    process =
2157*593dc095SDavid du Colombier 		(((gs_font_type0 *)font)->data.FMapType == fmap_CMap ?
2158*593dc095SDavid du Colombier 		 process_cmap_text :
2159*593dc095SDavid du Colombier 		 process_composite_text);
2160*593dc095SDavid du Colombier 	    break;
2161*593dc095SDavid du Colombier 	default:
2162*593dc095SDavid du Colombier 	    goto skip;
2163*593dc095SDavid du Colombier 	}
2164*593dc095SDavid du Colombier     }
2165*593dc095SDavid du Colombier 
2166*593dc095SDavid du Colombier     /*
2167*593dc095SDavid du Colombier      * We want to process the entire string in a single call, but we may
2168*593dc095SDavid du Colombier      * need to modify it.  Copy it to a buffer.  Note that it may consist
2169*593dc095SDavid du Colombier      * of bytes, gs_chars, or gs_glyphs.
2170*593dc095SDavid du Colombier      */
2171*593dc095SDavid du Colombier 
2172*593dc095SDavid du Colombier     if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES))
2173*593dc095SDavid du Colombier 	DO_NOTHING;
2174*593dc095SDavid du Colombier     else if (operation & TEXT_FROM_CHARS)
2175*593dc095SDavid du Colombier 	size *= sizeof(gs_char);
2176*593dc095SDavid du Colombier     else if (operation & TEXT_FROM_SINGLE_CHAR)
2177*593dc095SDavid du Colombier 	size = sizeof(gs_char);
2178*593dc095SDavid du Colombier     else if (operation & TEXT_FROM_GLYPHS)
2179*593dc095SDavid du Colombier 	size *= sizeof(gs_glyph);
2180*593dc095SDavid du Colombier     else if (operation & TEXT_FROM_SINGLE_GLYPH)
2181*593dc095SDavid du Colombier 	size = sizeof(gs_glyph);
2182*593dc095SDavid du Colombier     else
2183*593dc095SDavid du Colombier 	goto skip;
2184*593dc095SDavid du Colombier 
2185*593dc095SDavid du Colombier     if (size <= sizeof(buf)) {
2186*593dc095SDavid du Colombier 	code = process(pte, buf.bytes, size);
2187*593dc095SDavid du Colombier     } else {
2188*593dc095SDavid du Colombier 	byte *buf = gs_alloc_string(pte->memory, size, "pdf_text_process");
2189*593dc095SDavid du Colombier 
2190*593dc095SDavid du Colombier 	if (buf == 0)
2191*593dc095SDavid du Colombier 	    return_error(gs_error_VMerror);
2192*593dc095SDavid du Colombier 	code = process(pte, buf, size);
2193*593dc095SDavid du Colombier 	gs_free_string(pte->memory, buf, size, "pdf_text_process");
2194*593dc095SDavid du Colombier     }
2195*593dc095SDavid du Colombier  skip:
2196*593dc095SDavid du Colombier     if (code < 0 ||
2197*593dc095SDavid du Colombier 	    (pte->current_font->FontType == ft_user_defined &&
2198*593dc095SDavid du Colombier 	     code != TEXT_PROCESS_INTERVENE &&
2199*593dc095SDavid du Colombier 	    penum->index < penum->text.size)) {
2200*593dc095SDavid du Colombier 	if (code == gs_error_unregistered) /* Debug purpose only. */
2201*593dc095SDavid du Colombier 	    return code;
2202*593dc095SDavid du Colombier 	if (code == gs_error_VMerror)
2203*593dc095SDavid du Colombier 	    return code;
2204*593dc095SDavid du Colombier  default_impl:
2205*593dc095SDavid du Colombier 	/* Fall back to the default implementation. */
2206*593dc095SDavid du Colombier 	code = pdf_default_text_begin(pte, &pte->text, &pte_default);
2207*593dc095SDavid du Colombier 	if (code < 0)
2208*593dc095SDavid du Colombier 	    return code;
2209*593dc095SDavid du Colombier 	penum->pte_default = pte_default;
2210*593dc095SDavid du Colombier 	gs_text_enum_copy_dynamic(pte_default, pte, false);
2211*593dc095SDavid du Colombier     }
2212*593dc095SDavid du Colombier     /* The 'process' procedure might also have set pte_default itself. */
2213*593dc095SDavid du Colombier     if (penum->pte_default && !code)
2214*593dc095SDavid du Colombier 	goto top;
2215*593dc095SDavid du Colombier     return code;
2216*593dc095SDavid du Colombier     /*
2217*593dc095SDavid du Colombier      * This function uses an unobvious algorithm while handling type 3 fonts.
2218*593dc095SDavid du Colombier      * It runs 'process' to copy text until a glyph, which was not copied to
2219*593dc095SDavid du Colombier      * output font. Then it installs pte_default and falls back to default
2220*593dc095SDavid du Colombier      * implementation with PS interpreter callout. The callout executes
2221*593dc095SDavid du Colombier      * BuildChar/BuildGlyph with setcachedevice. The latter calls
2222*593dc095SDavid du Colombier      * pdf_set_charproc_attrs, which sets up an accumulator
2223*593dc095SDavid du Colombier      * of graphic objects to a pdf_begin_resource stream.
2224*593dc095SDavid du Colombier      * When the callout completes, pdf_text_process calls pdf_end_charproc_accum
2225*593dc095SDavid du Colombier      * and later resumes the normal (non-default) text enumeration, repeating the
2226*593dc095SDavid du Colombier      * the "callouted" glyph AT SECOND TIME. We can't do without the second pass
2227*593dc095SDavid du Colombier      * becauase in the first pass the glyph widths is unknown.
2228*593dc095SDavid du Colombier      */
2229*593dc095SDavid du Colombier      /*
2230*593dc095SDavid du Colombier       * Another unobvious thing is a CDevProc callout.
2231*593dc095SDavid du Colombier       * If 'process' returns with TEXT_PROCESS_CDEVPROC,
2232*593dc095SDavid du Colombier       * an interpreter callout will happen, and the function will be called again
2233*593dc095SDavid du Colombier       * with pte->cdevproc_result_valid = true. Then it restatrs with taking
2234*593dc095SDavid du Colombier       * glyph metrics from pte->cdevproc_result instead obtaining them with
2235*593dc095SDavid du Colombier       * font->procs.glyph_info .
2236*593dc095SDavid du Colombier       */
2237*593dc095SDavid du Colombier }
2238