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