1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* Encoding-based (Type 1/2/42) text processing for pdfwrite. */
18
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsutil.h"
24 #include "gxfcmap.h"
25 #include "gxfcopy.h"
26 #include "gxfont.h"
27 #include "gxfont0.h"
28 #include "gxfont0c.h"
29 #include "gxpath.h" /* for getting current point */
30 #include "gxchar.h" /* for gx_compute_text_oversampling & gx_lookup_cached_char */
31 #include "gxfcache.h" /* for gx_lookup_fm_pair */
32 #include "gdevpsf.h"
33 #include "gdevpdfx.h"
34 #include "gdevpdfg.h"
35 #include "gdevpdfo.h"
36 #include "gdevpdtx.h"
37 #include "gdevpdtd.h"
38 #include "gdevpdtf.h"
39 #include "gdevpdts.h"
40 #include "gdevpdtt.h"
41
42 #include "gximage.h"
43 #include "gxcpath.h"
44
45 #include "gsfcmap.h"
46
47 static int pdf_char_widths(gx_device_pdf *const pdev,
48 pdf_font_resource_t *pdfont, int ch,
49 gs_font_base *font,
50 pdf_glyph_widths_t *pwidths /* may be NULL */);
51 static int pdf_process_string(pdf_text_enum_t *penum, gs_string *pstr,
52 const gs_matrix *pfmat,
53 pdf_text_process_state_t *ppts,
54 const gs_glyph *gdata);
55
56 /*
57 * Process a string with a simple gs_font.
58 */
59 int
pdf_process_string_aux(pdf_text_enum_t * penum,gs_string * pstr,const gs_glyph * gdata,const gs_matrix * pfmat,pdf_text_process_state_t * ppts)60 pdf_process_string_aux(pdf_text_enum_t *penum, gs_string *pstr,
61 const gs_glyph *gdata, const gs_matrix *pfmat,
62 pdf_text_process_state_t *ppts)
63 {
64 gs_font_base *font = (gs_font_base *)penum->current_font;
65
66 switch (font->FontType) {
67 case ft_TrueType:
68 case ft_encrypted:
69 case ft_encrypted2:
70 case ft_user_defined:
71 case ft_PDF_user_defined:
72 case ft_PCL_user_defined:
73 case ft_GL2_stick_user_defined:
74 case ft_GL2_531:
75 case ft_MicroType:
76 break;
77 default:
78 return_error(gs_error_rangecheck);
79 }
80 return pdf_process_string(penum, pstr, pfmat, ppts, gdata);
81 }
82
83 /*
84 * Add char code pair to ToUnicode CMap,
85 * creating the CMap on neccessity.
86 */
87 int
pdf_add_ToUnicode(gx_device_pdf * pdev,gs_font * font,pdf_font_resource_t * pdfont,gs_glyph glyph,gs_char ch,const gs_const_string * gnstr)88 pdf_add_ToUnicode(gx_device_pdf *pdev, gs_font *font, pdf_font_resource_t *pdfont,
89 gs_glyph glyph, gs_char ch, const gs_const_string *gnstr)
90 { int code;
91 gs_char length;
92 ushort *unicode = 0;
93
94 if (glyph == GS_NO_GLYPH)
95 return 0;
96 length = font->procs.decode_glyph((gs_font *)font, glyph, ch, NULL, 0);
97 if ((length == 0 || length == GS_NO_CHAR) && gnstr != NULL && gnstr->size == 7) {
98 if (!memcmp(gnstr->data, "uni", 3)) {
99 static const char *hexdigits = "0123456789ABCDEF";
100 char *d0 = strchr(hexdigits, gnstr->data[3]);
101 char *d1 = strchr(hexdigits, gnstr->data[4]);
102 char *d2 = strchr(hexdigits, gnstr->data[5]);
103 char *d3 = strchr(hexdigits, gnstr->data[6]);
104
105 unicode = (ushort *)gs_alloc_bytes(pdev->memory, sizeof(ushort), "temporary Unicode array");
106 if (d0 != NULL && d1 != NULL && d2 != NULL && d3 != NULL) {
107 char *u = (char *)unicode;
108 u[0] = ((d0 - hexdigits) << 4) + ((d1 - hexdigits));
109 u[1] = ((d2 - hexdigits) << 4) + ((d3 - hexdigits));
110 length = 2;
111 }
112 }
113 }
114
115 if (length != 0 && length != GS_NO_CHAR) {
116 if (pdfont->cmap_ToUnicode == NULL) {
117 /* ToUnicode CMaps are always encoded with two byte keys. See
118 * Technical Note 5411, 'ToUnicode Mapping File Tutorial'
119 * page 3.
120 */
121 /* Unfortunately, the above is not true. See the PDF Reference (version 1.7
122 * p 472 'ToUnicode CMaps'. Even that documentation is incorrect as it
123 * describes codespaceranges, in fact for Acrobat this is irrelevant,
124 * but the bfranges must be one byte for simple fonts. By altering the
125 * key size for CID fonts we can write both consistently correct.
126 */
127 uint num_codes = 256, key_size = 1;
128
129 if (font->FontType == ft_CID_encrypted) {
130 gs_font_cid0 *pfcid = (gs_font_cid0 *)font;
131
132 num_codes = pfcid->cidata.common.CIDCount;
133 key_size = 2;
134 } else if (font->FontType == ft_CID_TrueType || font->FontType == ft_composite) {
135 key_size = 2;
136 /* Since PScript5.dll creates GlyphNames2Unicode with character codes
137 instead CIDs, and with the WinCharSetFFFF-H2 CMap
138 character codes appears from the range 0-0xFFFF (Bug 687954),
139 we must use the maximal character code value for the ToUnicode
140 code count. */
141 num_codes = 65536;
142 }
143 code = gs_cmap_ToUnicode_alloc(pdev->pdf_memory, pdfont->rid, num_codes, key_size, length,
144 &pdfont->cmap_ToUnicode);
145 if (code < 0) {
146 if (unicode)
147 gs_free_object(pdev->memory, unicode, "temporary Unicode array");
148 return code;
149 }
150 } else {
151 if (((gs_cmap_ToUnicode_t *)pdfont->cmap_ToUnicode)->value_size < length){
152 gs_cmap_ToUnicode_realloc(pdev->pdf_memory, length, &pdfont->cmap_ToUnicode);
153 }
154 }
155
156 if (!unicode) {
157 unicode = (ushort *)gs_alloc_bytes(pdev->memory, length * sizeof(short), "temporary Unicode array");
158 length = font->procs.decode_glyph((gs_font *)font, glyph, ch, unicode, length);
159 }
160
161 if (pdfont->cmap_ToUnicode != NULL)
162 gs_cmap_ToUnicode_add_pair(pdfont->cmap_ToUnicode, ch, unicode, length);
163 }
164 if (unicode)
165 gs_free_object(pdev->memory, unicode, "temporary Unicode array");
166 return 0;
167 }
168
169 typedef struct {
170 gx_device_pdf *pdev;
171 pdf_resource_type_t rtype;
172 } pdf_resource_enum_data_t;
173
174 static int
process_resources2(void * client_data,const byte * key_data,uint key_size,const cos_value_t * v)175 process_resources2(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v)
176 {
177 pdf_resource_enum_data_t *data = (pdf_resource_enum_data_t *)client_data;
178 pdf_resource_t *pres = pdf_find_resource_by_resource_id(data->pdev, data->rtype, v->contents.object->id);
179
180 if (pres == NULL)
181 return_error(gs_error_unregistered); /* Must not happen. */
182 pres->where_used |= data->pdev->used_mask;
183 return 0;
184 }
185
186 static int
process_resources1(void * client_data,const byte * key_data,uint key_size,const cos_value_t * v)187 process_resources1(void *client_data, const byte *key_data, uint key_size, const cos_value_t *v)
188 {
189 pdf_resource_enum_data_t *data = (pdf_resource_enum_data_t *)client_data;
190 static const char *rn[] = {PDF_RESOURCE_TYPE_NAMES};
191 int i;
192
193 for (i = 0; i < count_of(rn); i++) {
194 if (rn[i] != NULL && !bytes_compare((const byte *)rn[i], strlen(rn[i]), key_data, key_size))
195 break;
196 }
197 if (i >= count_of(rn))
198 return 0;
199 data->rtype = i;
200 return cos_dict_forall((cos_dict_t *)v->contents.object, data, process_resources2);
201 }
202
203 /*
204 * Register charproc fonts with the page or substream.
205 */
206 int
pdf_used_charproc_resources(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)207 pdf_used_charproc_resources(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
208 {
209 if (pdfont->where_used & pdev->used_mask)
210 return 0;
211 pdfont->where_used |= pdev->used_mask;
212 if (pdev->CompatibilityLevel >= 1.2)
213 return 0;
214 if (pdfont->FontType == ft_user_defined ||
215 pdfont->FontType == ft_PDF_user_defined ||
216 pdfont->FontType == ft_PCL_user_defined ||
217 pdfont->FontType == ft_MicroType ||
218 pdfont->FontType == ft_GL2_stick_user_defined ||
219 pdfont->FontType == ft_GL2_531) {
220 pdf_resource_enum_data_t data;
221
222 data.pdev = pdev;
223 return cos_dict_forall(pdfont->u.simple.s.type3.Resources, &data, process_resources1);
224 }
225 return 0;
226 }
227
228 /*
229 * Given a text string and a simple gs_font, return a font resource suitable
230 * for the text string, possibly re-encoding the string. This
231 * may involve creating a font resource and/or adding glyphs and/or Encoding
232 * entries to it.
233 *
234 * Sets *ppdfont.
235 */
236 static int
pdf_encode_string_element(gx_device_pdf * pdev,gs_font * font,pdf_font_resource_t * pdfont,gs_char ch,const gs_glyph * gdata)237 pdf_encode_string_element(gx_device_pdf *pdev, gs_font *font, pdf_font_resource_t *pdfont,
238 gs_char ch, const gs_glyph *gdata)
239 {
240 gs_font_base *cfont, *ccfont;
241 int code;
242 gs_glyph copied_glyph;
243 gs_const_string gnstr;
244 pdf_encoding_element_t *pet;
245 gs_glyph glyph;
246
247 /*
248 * In contradiction with pre-7.20 versions of pdfwrite,
249 * we never re-encode texts due to possible encoding conflict while font merging.
250 */
251 cfont = pdf_font_resource_font(pdfont, false);
252 ccfont = pdf_font_resource_font(pdfont, true);
253 pet = &pdfont->u.simple.Encoding[ch];
254 glyph = (gdata == NULL ? font->procs.encode_char(font, ch, GLYPH_SPACE_NAME)
255 : *gdata);
256 if (glyph == GS_NO_GLYPH || glyph == pet->glyph)
257 return 0;
258 if (pet->glyph != GS_NO_GLYPH) { /* encoding conflict */
259 return_error(gs_error_rangecheck);
260 /* Must not happen because pdf_obtain_font_resource
261 * checks for encoding compatibility.
262 */
263 }
264 code = font->procs.glyph_name(font, glyph, &gnstr);
265 if (code < 0)
266 return code; /* can't get name of glyph */
267 if (font->FontType != ft_user_defined &&
268 font->FontType != ft_PDF_user_defined &&
269 font->FontType != ft_PCL_user_defined &&
270 font->FontType != ft_MicroType &&
271 font->FontType != ft_GL2_stick_user_defined &&
272 font->FontType != ft_GL2_531) {
273 /* The standard 14 fonts don't have a FontDescriptor. */
274 code = (pdfont->base_font != 0 ?
275 pdf_base_font_copy_glyph(pdfont->base_font, glyph, (gs_font_base *)font) :
276 pdf_font_used_glyph(pdfont->FontDescriptor, glyph, (gs_font_base *)font));
277 if (code < 0 && code != gs_error_undefined)
278 return code;
279 if (code == gs_error_undefined) {
280 if (pdev->PDFA != 0 || pdev->PDFX) {
281 switch (pdev->PDFACompatibilityPolicy) {
282 case 0:
283 emprintf(pdev->memory,
284 "Requested glyph not present in source font,\n not permitted in PDF/A, reverting to normal PDF output\n");
285 pdev->AbortPDFAX = true;
286 pdev->PDFA = 0;
287 break;
288 case 1:
289 emprintf(pdev->memory,
290 "Requested glyph not present in source font,\n not permitted in PDF/A, glyph will not be present in output file\n\n");
291 /* Returning an error causees text processing to try and
292 * handle the glyph by rendering to a bitmap instead of
293 * as a glyph in a font. This will eliminate the problem
294 * and the fiel should appear the same as the original.
295 */
296 return_error(gs_error_unknownerror);
297 break;
298 case 2:
299 emprintf(pdev->memory,
300 "Requested glyph not present in source font,\n not permitted in PDF/A, aborting conversion\n");
301 /* Careful here, only certain errors will bubble up
302 * through the text processing.
303 */
304 return_error(gs_error_invalidfont);
305 break;
306 default:
307 emprintf(pdev->memory,
308 "Requested glyph not present in source font,\n not permitted in PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
309 pdev->AbortPDFAX = true;
310 pdev->PDFA = 0;
311 break;
312 }
313 }
314 /* PS font has no such glyph. */
315 if (bytes_compare(gnstr.data, gnstr.size, (const byte *)".notdef", 7)) {
316 pet->glyph = glyph;
317 pet->str = gnstr;
318 pet->is_difference = true;
319 }
320 } else if (pdfont->base_font == NULL && ccfont != NULL &&
321 (gs_copy_glyph_options(font, glyph, (gs_font *)ccfont, COPY_GLYPH_NO_NEW) != 1 ||
322 gs_copied_font_add_encoding((gs_font *)ccfont, ch, glyph) < 0)) {
323 /*
324 * The "complete" copy of the font appears incomplete
325 * due to incrementally added glyphs. Drop the "complete"
326 * copy now and continue with subset font only.
327 *
328 * Note that we need to add the glyph to the encoding of the
329 * "complete" font, because "PPI-ProPag 2.6.1.4 (archivePg)"
330 * creates multiple font copies with reduced encodings
331 * (we believe it is poorly designed),
332 * and we can merge the copies back to a single font (see Bug 686875).
333 * We also check whether the encoding is compatible.
334 * It must be compatible here due to the pdf_obtain_font_resource
335 * and ccfont logics, but we want to ensure for safety reason.
336 */
337 ccfont = NULL;
338 pdf_font_descriptor_drop_complete_font(pdfont->FontDescriptor);
339 }
340 /*
341 * We arbitrarily allow the first encoded character in a given
342 * position to determine the encoding associated with the copied
343 * font.
344 */
345 copied_glyph = cfont->procs.encode_char((gs_font *)cfont, ch,
346 GLYPH_SPACE_NAME);
347 if (glyph != copied_glyph &&
348 gs_copied_font_add_encoding((gs_font *)cfont, ch, glyph) < 0
349 )
350 pet->is_difference = true;
351 pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
352 }
353 /*
354 * We always generate ToUnicode for simple fonts, because
355 * we can't detemine in advance, which glyphs the font actually uses.
356 * The decision about writing it out is deferred until pdf_write_font_resource.
357 */
358 code = pdf_add_ToUnicode(pdev, font, pdfont, glyph, ch, &gnstr);
359 if (code < 0)
360 return code;
361 pet->glyph = glyph;
362 pet->str = gnstr;
363 return 0;
364 }
365
366 /*
367 * Estimate text bbox.
368 */
369 static int
process_text_estimate_bbox(pdf_text_enum_t * pte,gs_font_base * font,const gs_const_string * pstr,const gs_matrix * pfmat,gs_rect * text_bbox,gs_point * pdpt)370 process_text_estimate_bbox(pdf_text_enum_t *pte, gs_font_base *font,
371 const gs_const_string *pstr,
372 const gs_matrix *pfmat,
373 gs_rect *text_bbox, gs_point *pdpt)
374 {
375 int i;
376 int space_char =
377 (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ?
378 pte->text.space.s_char : -1);
379 int WMode = font->WMode;
380 int code = 0;
381 gs_point total = {0, 0};
382 gs_point p0, p1, p2, p3;
383 gs_fixed_point origin;
384 gs_matrix m;
385 int xy_index = pte->xy_index, info_flags = 0;
386
387 code = gx_path_current_point(pte->path, &origin);
388 if (code < 0)
389 return code;
390 m = ctm_only(pte->pgs);
391 m.tx = fixed2float(origin.x);
392 m.ty = fixed2float(origin.y);
393 gs_matrix_multiply(pfmat, &m, &m);
394
395 /* If the FontBBox is all 0, then its clearly wrong, so determine the text width
396 * accurately by processing the glyph program.
397 */
398 if (font->FontBBox.p.x == font->FontBBox.q.x ||
399 font->FontBBox.p.y == font->FontBBox.q.y) {
400 info_flags = GLYPH_INFO_BBOX | GLYPH_INFO_WIDTH0 << WMode;
401 } else {
402 double width, height;
403
404 /* This is a heuristic for Bug #700124. We try to determine whether a given glyph
405 * is used in a string by using the current point, glyph width and advance width
406 * to see if the glyph is fully clipped out, if it is we don't include it in the
407 * output, or in subset fonts.
408 *
409 * Previously we used the FontBBox to determine a quick glyph width, but
410 * in bug #699454 and bug #699571 we saw that OneVision EPSExport could construct
411 * fonts with a wildly incorrect BBox ([0 0 2 1]) and then draw the text without
412 * an advance width, leading us to conclude the glyph was clipped out and eliding it.
413 *
414 * To solve this we added code to process the glyph program and extract an accurate
415 * width of the glyph. However, this proved slow. So here we attempt to decide if
416 * the FontBBox is sensible by applying the FontMatrix to it, and looking to see
417 * if that results in a reasonable number of co-ordinates in font space. If it
418 * does then we use the FontBBox for speed, otherwise we carefully process the
419 * glyphs in the font and extract their accurate widths.
420 */
421 gs_point_transform(font->FontBBox.p.x, font->FontBBox.p.y, &font->FontMatrix, &p0);
422 gs_point_transform(font->FontBBox.p.x, font->FontBBox.q.y, &font->FontMatrix, &p1);
423 gs_point_transform(font->FontBBox.q.x, font->FontBBox.p.y, &font->FontMatrix, &p2);
424 gs_point_transform(font->FontBBox.q.x, font->FontBBox.q.y, &font->FontMatrix, &p3);
425 width = max(fabs(p2.x), fabs(p3.x)) - p0.x;
426 height = max(fabs(p1.y), fabs(p3.y)) - p0.y;
427
428 /* Yes, this is a magic number. There's no reasoning here, its just a guess, we may
429 * need to adjust this in future. Or possibly do away with it altogether if it proves
430 * unreliable.
431 */
432 if (fabs(width) < 0.1 || fabs(height) < 0.1) {
433 info_flags = GLYPH_INFO_BBOX | GLYPH_INFO_WIDTH0 << WMode;
434 } else {
435 gs_point_transform(font->FontBBox.p.x, font->FontBBox.p.y, &m, &p0);
436 gs_point_transform(font->FontBBox.p.x, font->FontBBox.q.y, &m, &p1);
437 gs_point_transform(font->FontBBox.q.x, font->FontBBox.p.y, &m, &p2);
438 gs_point_transform(font->FontBBox.q.x, font->FontBBox.q.y, &m, &p3);
439 info_flags = GLYPH_INFO_WIDTH0 << WMode;
440 }
441 }
442
443 for (i = 0; i < pstr->size; ++i) {
444 byte c = pstr->data[i];
445 gs_rect bbox;
446 gs_point wanted, tpt;
447 gs_glyph glyph = font->procs.encode_char((gs_font *)font, c,
448 GLYPH_SPACE_NAME);
449 gs_glyph_info_t info;
450 int code;
451
452 if (glyph == GS_NO_GLYPH)
453 return_error (gs_error_invalidfont);
454
455 memset(&info, 0x00, sizeof(gs_glyph_info_t));
456 code = font->procs.glyph_info((gs_font *)font, glyph, NULL,
457 info_flags,
458 &info);
459
460 /* If we got an undefined error, and its a type 1/CFF font, try to
461 * find the /.notdef glyph and use its width instead (as this is the
462 * glyph which will be rendered). We don't do this for other font types
463 * as it seems Acrobat/Distiller may not do so either.
464 */
465 /* The GL/2 stick font does not supply the enumerate_glyphs method,
466 * *and* leaves it uninitialised. But it should not be possible to
467 * get an undefiend error with this font anyway.
468 */
469 if (code < 0) {
470 if ((font->FontType == ft_encrypted ||
471 font->FontType == ft_encrypted2)) {
472 int index;
473
474 for (index = 0;
475 (font->procs.enumerate_glyph((gs_font *)font, &index,
476 (GLYPH_SPACE_NAME), &glyph)) >= 0 &&
477 index != 0;) {
478
479 if (gs_font_glyph_is_notdef(font, glyph)) {
480 code = font->procs.glyph_info((gs_font *)font, glyph, NULL,
481 info_flags,
482 &info);
483
484 if (code < 0)
485 return code;
486 }
487 break;
488 }
489 }
490 if (code < 0)
491 return code;
492 }
493 if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
494 gs_text_replaced_width(&pte->text, xy_index++, &tpt);
495 gs_distance_transform(tpt.x, tpt.y, &ctm_only(pte->pgs), &wanted);
496 } else {
497 gs_distance_transform(info.width[WMode].x,
498 info.width[WMode].y,
499 &m, &wanted);
500 if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
501 gs_distance_transform(pte->text.delta_all.x,
502 pte->text.delta_all.y,
503 &ctm_only(pte->pgs), &tpt);
504 wanted.x += tpt.x;
505 wanted.y += tpt.y;
506 }
507 if (pstr->data[i] == space_char && pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) {
508 gs_distance_transform(pte->text.delta_space.x,
509 pte->text.delta_space.y,
510 &ctm_only(pte->pgs), &tpt);
511 wanted.x += tpt.x;
512 wanted.y += tpt.y;
513 }
514 }
515
516 if (info_flags & GLYPH_INFO_BBOX) {
517 gs_point_transform(info.bbox.p.x, info.bbox.p.x, &m, &p0);
518 gs_point_transform(info.bbox.p.x, info.bbox.q.y, &m, &p1);
519 gs_point_transform(info.bbox.q.x, info.bbox.p.y, &m, &p2);
520 gs_point_transform(info.bbox.q.x, info.bbox.q.y, &m, &p3);
521 }
522
523 bbox.p.x = min(min(p0.x, p1.x), min(p2.x, p3.x));
524 bbox.p.y = min(min(p0.y, p1.y), min(p2.y, p3.y));
525 bbox.q.x = max(max(p0.x, p1.x), max(p2.x, p3.x));
526 bbox.q.y = max(max(p0.y, p1.y), max(p2.y, p3.y));
527
528 bbox.q.x = bbox.p.x + max(bbox.q.x - bbox.p.x, wanted.x);
529 bbox.q.y = bbox.p.y + max(bbox.q.y - bbox.p.y, wanted.y);
530 bbox.p.x += total.x;
531 bbox.p.y += total.y;
532 bbox.q.x += total.x;
533 bbox.q.y += total.y;
534
535 total.x += wanted.x;
536 total.y += wanted.y;
537
538 if (i == 0)
539 *text_bbox = bbox;
540 else
541 rect_merge(*text_bbox, bbox);
542 }
543 *pdpt = total;
544 return 0;
545 }
546
547 void
adjust_first_last_char(pdf_font_resource_t * pdfont,byte * str,int size)548 adjust_first_last_char(pdf_font_resource_t *pdfont, byte *str, int size)
549 {
550 int i;
551
552 for (i = 0; i < size; ++i) {
553 int chr = str[i];
554
555 if (chr < pdfont->u.simple.FirstChar)
556 pdfont->u.simple.FirstChar = chr;
557 if (chr > pdfont->u.simple.LastChar)
558 pdfont->u.simple.LastChar = chr;
559 }
560 }
561
562 int
pdf_shift_text_currentpoint(pdf_text_enum_t * penum,gs_point * wpt)563 pdf_shift_text_currentpoint(pdf_text_enum_t *penum, gs_point *wpt)
564 {
565 return gs_moveto_aux(penum->pgs, gx_current_path(penum->pgs),
566 fixed2float(penum->origin.x) + wpt->x,
567 fixed2float(penum->origin.y) + wpt->y);
568 }
569
570 /*
571 * Internal procedure to process a string in a non-composite font.
572 * Doesn't use or set pte->{data,size,index}; may use/set pte->xy_index;
573 * may set penum->returned.total_width. Sets ppts->values.
574 *
575 * Note that the caller is responsible for re-encoding the string, if
576 * necessary; for adding Encoding entries in pdfont; and for copying any
577 * necessary glyphs. penum->current_font provides the gs_font for getting
578 * glyph metrics, but this font's Encoding is not used.
579 */
580 static int process_text_return_width(const pdf_text_enum_t *pte,
581 gs_font_base *font,
582 pdf_text_process_state_t *ppts,
583 const gs_const_string *pstr, const gs_glyph *gdata,
584 gs_point *pdpt, int *accepted, gs_rect *bbox);
585 static int
pdf_process_string(pdf_text_enum_t * penum,gs_string * pstr,const gs_matrix * pfmat,pdf_text_process_state_t * ppts,const gs_glyph * gdata)586 pdf_process_string(pdf_text_enum_t *penum, gs_string *pstr,
587 const gs_matrix *pfmat,
588 pdf_text_process_state_t *ppts, const gs_glyph *gdata)
589 {
590 gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev;
591 gs_font_base *font = (gs_font_base *)penum->current_font;
592 pdf_font_resource_t *pdfont;
593 gs_text_params_t *text = &penum->text;
594 int code = 0, mask;
595 gs_point width_pt;
596 int accepted;
597 gs_rect text_bbox = {{0, 0}, {0, 0}}, glyphs_bbox = {{10000,10000}, {0,0}};
598 unsigned int operation = text->operation;
599
600 code = pdf_obtain_font_resource(penum, pstr, &pdfont);
601 if (code < 0)
602 return code;
603 if (pfmat == 0)
604 pfmat = &font->FontMatrix;
605 if (text->operation & TEXT_RETURN_WIDTH) {
606 code = gx_path_current_point(penum->path, &penum->origin);
607 if (code < 0)
608 return code;
609 }
610 if (text->size == 0)
611 return 0;
612 if (penum->pgs->text_rendering_mode != 3 && !(text->operation & TEXT_DO_NONE)) {
613 /*
614 * Acrobat Reader can't handle text with huge coordinates,
615 * so don't emit the text if it is outside the clip bbox
616 * (Note : it ever fails with type 3 fonts).
617 */
618
619 code = process_text_estimate_bbox(penum, font, (gs_const_string *)pstr, pfmat,
620 &text_bbox, &width_pt);
621 if (code == 0) {
622 gs_fixed_rect clip_bbox;
623 gs_rect rect;
624
625 if (penum->pcpath) {
626 gx_cpath_outer_box(penum->pcpath, &clip_bbox);
627 rect.p.x = fixed2float(clip_bbox.p.x);
628 rect.p.y = fixed2float(clip_bbox.p.y);
629 rect.q.x = fixed2float(clip_bbox.q.x);
630 rect.q.y = fixed2float(clip_bbox.q.y);
631 rect_intersect(rect, text_bbox);
632 if (rect.p.x > rect.q.x || rect.p.y > rect.q.y) {
633 penum->index += pstr->size;
634 text->operation &= ~TEXT_DO_DRAW;
635 }
636 }
637 } else {
638 gs_matrix m;
639 gs_fixed_point origin;
640 gs_point p0, p1, p2, p3;
641
642 code = gx_path_current_point(penum->path, &origin);
643 if (code < 0)
644 goto done;
645
646 m = ctm_only(penum->pgs);
647 m.tx = fixed2float(origin.x);
648 m.ty = fixed2float(origin.y);
649 gs_matrix_multiply(pfmat, &m, &m);
650
651 if (font->FontBBox.p.x != font->FontBBox.q.x) {
652 text_bbox.p.x = font->FontBBox.p.x;
653 text_bbox.q.x = font->FontBBox.q.x;
654 } else {
655 text_bbox.p.x = 0;
656 text_bbox.q.x = 1000;
657 }
658 if (font->FontBBox.p.y != font->FontBBox.q.y) {
659 text_bbox.p.y = font->FontBBox.p.y;
660 text_bbox.q.y = font->FontBBox.q.y;
661 } else {
662 text_bbox.p.y = 0;
663 text_bbox.q.y = 1000;
664 }
665 gs_point_transform(text_bbox.p.x, text_bbox.p.y, &m, &p0);
666 gs_point_transform(text_bbox.p.x, text_bbox.q.y, &m, &p1);
667 gs_point_transform(text_bbox.q.x, text_bbox.p.y, &m, &p2);
668 gs_point_transform(text_bbox.q.x, text_bbox.q.y, &m, &p3);
669 text_bbox.p.x = min(min(p0.x, p1.x), min(p1.x, p2.x));
670 text_bbox.p.y = min(min(p0.y, p1.y), min(p1.y, p2.y));
671 text_bbox.q.x = max(max(p0.x, p1.x), max(p1.x, p2.x));
672 text_bbox.q.y = max(max(p0.y, p1.y), max(p1.y, p2.y));
673 }
674 } else {
675 /* We have no penum->pcpath. */
676 }
677
678 /*
679 * Note that pdf_update_text_state sets all the members of ppts->values
680 * to their current values.
681 */
682 code = pdf_update_text_state(ppts, penum, pdfont, pfmat);
683 if (code > 0) {
684 /* Try not to emulate ADD_TO_WIDTH if we don't have to. */
685 if (code & TEXT_ADD_TO_SPACE_WIDTH) {
686 if (!memchr(pstr->data, penum->text.space.s_char, pstr->size))
687 code &= ~TEXT_ADD_TO_SPACE_WIDTH;
688 }
689 }
690 if (code < 0)
691 goto done;
692 mask = code;
693
694 if (text->operation & TEXT_REPLACE_WIDTHS)
695 mask |= TEXT_REPLACE_WIDTHS;
696
697 /*
698 * The only operations left to handle are TEXT_DO_DRAW and
699 * TEXT_RETURN_WIDTH.
700 */
701 if (mask == 0) {
702 /*
703 * If any character has real_width != Width, we have to process
704 * the string character-by-character. process_text_return_width
705 * will tell us what we need to know.
706 */
707 if (!(text->operation & (TEXT_DO_DRAW | TEXT_RETURN_WIDTH))) {
708 code = 0;
709 goto done;
710 }
711 code = process_text_return_width(penum, font, ppts,
712 (gs_const_string *)pstr, gdata,
713 &width_pt, &accepted, &glyphs_bbox);
714 if (code < 0)
715 goto done;
716 if (code == 0) {
717 /* No characters with redefined widths -- the fast case. */
718 if (text->operation & TEXT_DO_DRAW || penum->pgs->text_rendering_mode == 3) {
719 code = pdf_append_chars(pdev, pstr->data, accepted,
720 width_pt.x, width_pt.y, false);
721 if (code < 0)
722 goto done;
723 adjust_first_last_char(pdfont, pstr->data, accepted);
724 penum->index += accepted;
725 } else if (text->operation & TEXT_DO_NONE)
726 penum->index += accepted;
727 } else {
728 /* Use the slow case. Set mask to any non-zero value. */
729 mask = TEXT_RETURN_WIDTH;
730 }
731 }
732 if (mask) {
733 /* process_text_modify_width destroys text parameters, save them now. */
734 int index0 = penum->index, xy_index = penum->xy_index;
735 gs_text_params_t text = penum->text;
736 int xy_index_step = (!(penum->text.operation & TEXT_REPLACE_WIDTHS) ? 0 :
737 penum->text.x_widths == penum->text.y_widths ? 2 : 1);
738 /* A glyphshow takes a shortcut by storing the single glyph directly into
739 * penum->text.data.d_glyph. However, process_text_modify_width
740 * replaces pte->text.data.bytes (these two are part of a union) with
741 * pstr->data, which is not valid for a glyphshow because it alters
742 * the glyph value store there. If we make a copy of the single glyph,
743 * it all works correctly.then
744 */
745 gs_glyph gdata_i, *gdata_p = (gs_glyph *)gdata;
746 if (penum->text.operation & TEXT_FROM_SINGLE_GLYPH) {
747 gdata_i = *gdata;
748 gdata_p = &gdata_i;
749 }
750
751 if (penum->text.operation & TEXT_REPLACE_WIDTHS) {
752 if (penum->text.x_widths != NULL)
753 penum->text.x_widths += xy_index * xy_index_step;
754 if (penum->text.y_widths != NULL)
755 penum->text.y_widths += xy_index * xy_index_step;
756 }
757 penum->xy_index = 0;
758 code = process_text_modify_width(penum, (gs_font *)font, ppts,
759 (gs_const_string *)pstr,
760 &width_pt, (const gs_glyph *)gdata_p, false, 1);
761 if (penum->text.operation & TEXT_REPLACE_WIDTHS) {
762 if (penum->text.x_widths != NULL)
763 penum->text.x_widths -= xy_index * xy_index_step;
764 if (penum->text.y_widths != NULL)
765 penum->text.y_widths -= xy_index * xy_index_step;
766 }
767 penum->xy_index += xy_index;
768 adjust_first_last_char(pdfont, pstr->data, penum->index);
769 penum->text = text;
770 penum->index += index0;
771 if (code < 0)
772 goto done;
773 }
774
775 /* Finally, return the total width if requested. */
776 if (pdev->Eps2Write && penum->pcpath) {
777 gx_device_clip cdev;
778 gx_drawing_color devc;
779 fixed x0, y0, bx2, by2;
780
781 if (glyphs_bbox.p.x != 10000 && glyphs_bbox.q.x != 0){
782 gs_matrix m;
783 gs_fixed_point origin;
784 gs_point p0, p1, p2, p3;
785
786 code = gx_path_current_point(penum->path, &origin);
787 if (code < 0)
788 return code;
789
790 m = ctm_only(penum->pgs);
791 m.tx = fixed2float(origin.x);
792 m.ty = fixed2float(origin.y);
793 gs_matrix_multiply(pfmat, &m, &m);
794
795 gs_point_transform(glyphs_bbox.p.x, glyphs_bbox.p.y, &m, &p0);
796 gs_point_transform(glyphs_bbox.p.x, glyphs_bbox.q.y, &m, &p1);
797 gs_point_transform(glyphs_bbox.q.x, glyphs_bbox.p.y, &m, &p2);
798 gs_point_transform(glyphs_bbox.q.x, glyphs_bbox.q.y, &m, &p3);
799 glyphs_bbox.p.x = min(min(p0.x, p1.x), min(p1.x, p2.x));
800 glyphs_bbox.p.y = min(min(p0.y, p1.y), min(p1.y, p2.y));
801 glyphs_bbox.q.x = max(max(p0.x, p1.x), max(p1.x, p2.x));
802 glyphs_bbox.q.y = max(max(p0.y, p1.y), max(p1.y, p2.y));
803 if (glyphs_bbox.p.y > text_bbox.p.y)
804 text_bbox.p.y = glyphs_bbox.p.y;
805 if (glyphs_bbox.q.y < text_bbox.q.y)
806 text_bbox.q.y = glyphs_bbox.q.y;
807 }
808 /* removed this section for bug #695671, where the rotated text
809 * doesn't contribute the 'height' of the text to the x dimension
810 * of the bounding box if this code is present. I can't see why
811 * this clamping was done, if it turns out to be required then
812 * we will need to revisit this and bug #695671.
813 text_bbox.p.x = fixed2float(penum->origin.x);
814 text_bbox.q.x = text_bbox.p.x + width_pt.x;
815 */
816
817 x0 = float2fixed(text_bbox.p.x);
818 y0 = float2fixed(text_bbox.p.y);
819 bx2 = float2fixed(text_bbox.q.x) - x0;
820 by2 = float2fixed(text_bbox.q.y) - y0;
821
822 pdev->AccumulatingBBox++;
823 gx_make_clip_device_on_stack(&cdev, penum->pcpath, (gx_device *)pdev);
824 set_nonclient_dev_color(&devc, gx_device_black((gx_device *)pdev)); /* any non-white color will do */
825 gx_default_fill_triangle((gx_device *) pdev, x0, y0,
826 float2fixed(text_bbox.p.x) - x0,
827 float2fixed(text_bbox.q.y) - y0,
828 bx2, by2, &devc, lop_default);
829 gx_default_fill_triangle((gx_device *) & cdev, x0, y0,
830 float2fixed(text_bbox.q.x) - x0,
831 float2fixed(text_bbox.p.y) - y0,
832 bx2, by2, &devc, lop_default);
833 pdev->AccumulatingBBox--;
834 }
835 if (!(operation & TEXT_RETURN_WIDTH)) {
836 code = 0;
837 goto done;
838 }
839 if (operation & TEXT_DO_NONE) {
840 /* stringwidth needs to transform to user space. */
841 gs_point p;
842
843 gs_distance_transform_inverse(width_pt.x, width_pt.y, &ctm_only(penum->pgs), &p);
844 penum->returned.total_width.x += p.x;
845 penum->returned.total_width.y += p.y;
846 } else
847 penum->returned.total_width = width_pt;
848 code = pdf_shift_text_currentpoint(penum, &width_pt);
849
850 done:
851 text->operation = operation;
852 return code;
853 }
854
855 /*
856 * Get the widths (unmodified and possibly modified) of a given character
857 * in a simple font. May add the widths to the widths cache (pdfont->Widths
858 * and pdf_font_cache_elem::real_widths). Return 1 if the widths were not cached.
859 */
860 static int
pdf_char_widths(gx_device_pdf * const pdev,pdf_font_resource_t * pdfont,int ch,gs_font_base * font,pdf_glyph_widths_t * pwidths)861 pdf_char_widths(gx_device_pdf *const pdev,
862 pdf_font_resource_t *pdfont, int ch, gs_font_base *font,
863 pdf_glyph_widths_t *pwidths /* may be NULL */)
864 {
865 pdf_glyph_widths_t widths;
866 int code;
867 byte *glyph_usage;
868 double *real_widths;
869 int char_cache_size, width_cache_size;
870 pdf_font_resource_t *pdfont1;
871
872 code = pdf_attached_font_resource(pdev, (gs_font *)font, &pdfont1,
873 &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
874 if (code < 0)
875 return code;
876 if (pdfont1 != pdfont)
877 return_error(gs_error_unregistered); /* Must not happen. */
878 if (ch < 0 || ch > 255)
879 return_error(gs_error_rangecheck);
880 if (ch >= width_cache_size)
881 return_error(gs_error_unregistered); /* Must not happen. */
882 if (pwidths == 0)
883 pwidths = &widths;
884 if ((font->FontType != ft_user_defined &&
885 font->FontType != ft_PDF_user_defined &&
886 font->FontType != ft_PCL_user_defined &&
887 font->FontType != ft_MicroType &&
888 font->FontType != ft_GL2_stick_user_defined &&
889 font->FontType != ft_GL2_531) && real_widths[ch] == 0) {
890 /* Might be an unused char, or just not cached. */
891 gs_glyph glyph = pdfont->u.simple.Encoding[ch].glyph;
892
893 code = pdf_glyph_widths(pdfont, font->WMode, glyph, (gs_font *)font, pwidths, NULL);
894 if (code < 0)
895 return code;
896 pwidths->BBox.p.x = pwidths->BBox.p.y = pwidths->BBox.q.x = pwidths->BBox.q.y = 0;
897 if (font->WMode != 0 && code > 0 && !pwidths->replaced_v) {
898 /*
899 * The font has no Metrics2, so it must write
900 * horizontally due to PS spec.
901 * Therefore we need to fill the Widths array,
902 * which is required by PDF spec.
903 * Take it from WMode==0.
904 */
905 code = pdf_glyph_widths(pdfont, 0, glyph, (gs_font *)font, pwidths, NULL);
906 }
907 if (pwidths->replaced_v) {
908 pdfont->u.simple.v[ch].x = pwidths->real_width.v.x - pwidths->Width.v.x;
909 pdfont->u.simple.v[ch].y = pwidths->real_width.v.y - pwidths->Width.v.y;
910 } else
911 pdfont->u.simple.v[ch].x = pdfont->u.simple.v[ch].y = 0;
912 if (code == 0) {
913 pdfont->Widths[ch] = pwidths->Width.w;
914 real_widths[ch] = pwidths->real_width.w;
915 } else {
916 if ((font->WMode == 0 || pwidths->ignore_wmode) && !pwidths->replaced_v)
917 pdfont->Widths[ch] = pwidths->real_width.w;
918 }
919 } else {
920 if (font->FontType == ft_user_defined || font->FontType == ft_PCL_user_defined ||
921 font->FontType == ft_MicroType || font->FontType == ft_GL2_stick_user_defined ||
922 font->FontType == ft_GL2_531 || font->FontType == ft_PDF_user_defined ) {
923 if (!(pdfont->used[ch >> 3] & 0x80 >> (ch & 7)))
924 return_error(gs_error_undefined); /* The charproc was not accumulated. */
925 if (!pdev->charproc_just_accumulated &&
926 !(pdfont->u.simple.s.type3.cached[ch >> 3] & 0x80 >> (ch & 7))) {
927 /* The charproc uses setcharwidth.
928 Need to accumulate again to check for a glyph variation. */
929 return_error(gs_error_undefined);
930 }
931 }
932 if (pdev->charproc_just_accumulated && (font->FontType == ft_user_defined || font->FontType == ft_PDF_user_defined)) {
933 pwidths->BBox.p.x = pdev->charproc_BBox.p.x;
934 pwidths->BBox.p.y = pdev->charproc_BBox.p.y;
935 pwidths->BBox.q.x = pdev->charproc_BBox.q.x;
936 pwidths->BBox.q.y = pdev->charproc_BBox.q.y;
937 }
938 pwidths->Width.w = pdfont->Widths[ch];
939 pwidths->Width.v = pdfont->u.simple.v[ch];
940 pwidths->real_width.v.x = pwidths->real_width.v.y = 0;
941 pwidths->ignore_wmode = false;
942 if (font->FontType == ft_user_defined || font->FontType == ft_PCL_user_defined ||
943 font->FontType == ft_MicroType || font->FontType == ft_GL2_stick_user_defined ||
944 font->FontType == ft_GL2_531 || font->FontType == ft_PDF_user_defined) {
945 pwidths->real_width.w = real_widths[ch * 2];
946 pwidths->Width.xy.x = pwidths->Width.w;
947 pwidths->Width.xy.y = 0;
948 pwidths->real_width.xy.x = real_widths[ch * 2 + 0];
949 pwidths->real_width.xy.y = real_widths[ch * 2 + 1];
950 pwidths->replaced_v = 0;
951 } else if (font->WMode) {
952 pwidths->real_width.w = real_widths[ch];
953 pwidths->Width.xy.x = 0;
954 pwidths->Width.xy.y = pwidths->Width.w;
955 pwidths->real_width.xy.x = 0;
956 pwidths->real_width.xy.y = pwidths->real_width.w;
957 } else {
958 pwidths->real_width.w = real_widths[ch];
959 pwidths->Width.xy.x = pwidths->Width.w;
960 pwidths->Width.xy.y = 0;
961 pwidths->real_width.xy.x = pwidths->real_width.w;
962 pwidths->real_width.xy.y = 0;
963 }
964 code = 0;
965 }
966 return code;
967 }
968
969 /*
970 * Convert glyph widths (.Width.xy and .real_widths.xy) from design to PDF text space
971 * Zero-out one of Width.xy.x/y per PDF Ref 5.3.3 "Text Space Details"
972 */
973 static void
pdf_char_widths_to_uts(pdf_font_resource_t * pdfont,pdf_glyph_widths_t * pwidths)974 pdf_char_widths_to_uts(pdf_font_resource_t *pdfont /* may be NULL for non-Type3 */,
975 pdf_glyph_widths_t *pwidths)
976 {
977 if (pdfont && (pdfont->FontType == ft_user_defined ||
978 pdfont->FontType == ft_PDF_user_defined ||
979 pdfont->FontType == ft_PCL_user_defined ||
980 pdfont->FontType == ft_MicroType ||
981 pdfont->FontType == ft_GL2_stick_user_defined ||
982 pdfont->FontType == ft_GL2_531)) {
983 gs_matrix *pmat = &pdfont->u.simple.s.type3.FontMatrix;
984
985 pwidths->Width.xy.x *= pmat->xx; /* formula simplified based on wy in glyph space == 0 */
986 pwidths->Width.xy.y = 0.0; /* WMode == 0 for PDF Type 3 fonts */
987 gs_distance_transform(pwidths->real_width.xy.x, pwidths->real_width.xy.y, pmat, &pwidths->real_width.xy);
988 } else {
989 /*
990 * For other font types:
991 * - PDF design->text space is a simple scaling by 0.001.
992 * - The Width.xy.x/y that should be zeroed-out per 5.3.3 "Text Space Details" is already 0.
993 */
994 pwidths->Width.xy.x /= 1000.0;
995 pwidths->Width.xy.y /= 1000.0;
996 pwidths->real_width.xy.x /= 1000.0;
997 pwidths->real_width.xy.y /= 1000.0;
998 }
999 }
1000
1001 /*
1002 * Compute the total text width (in user space). Return 1 if any
1003 * character had real_width != Width, otherwise 0.
1004 */
1005 static int
process_text_return_width(const pdf_text_enum_t * pte,gs_font_base * font,pdf_text_process_state_t * ppts,const gs_const_string * pstr,const gs_glyph * gdata,gs_point * pdpt,int * accepted,gs_rect * bbox)1006 process_text_return_width(const pdf_text_enum_t *pte, gs_font_base *font,
1007 pdf_text_process_state_t *ppts,
1008 const gs_const_string *pstr, const gs_glyph *gdata,
1009 gs_point *pdpt, int *accepted, gs_rect *bbox)
1010 {
1011 int i;
1012 gs_point w;
1013 gs_point dpt;
1014 int num_spaces = 0;
1015 int space_char =
1016 (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ?
1017 pte->text.space.s_char : -1);
1018 int widths_differ = 0, code;
1019 gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
1020 pdf_font_resource_t *pdfont;
1021
1022 code = pdf_attached_font_resource(pdev, (gs_font *)font, &pdfont, NULL, NULL, NULL, NULL);
1023 if (code < 0)
1024 return code;
1025 for (i = 0, w.x = w.y = 0; i < pstr->size; ++i) {
1026 pdf_glyph_widths_t cw; /* in PDF text space */
1027 gs_char ch = pstr->data[i];
1028
1029 /* Initialise some variables */
1030 cw.real_width.xy.x = cw.real_width.xy.y = cw.Width.xy.x = cw.Width.xy.y = 0;
1031 cw.BBox.p.x = cw.BBox.p.y = cw.BBox.q.x = cw.BBox.q.y = 0;
1032
1033 { const gs_glyph *gdata_i = (gdata != NULL ? gdata + i : 0);
1034
1035 code = pdf_encode_string_element(pdev, (gs_font *)font, pdfont, ch, gdata_i);
1036 if (code < 0)
1037 return code;
1038 }
1039 if ((font->FontType == ft_user_defined ||
1040 font->FontType == ft_PDF_user_defined ||
1041 font->FontType == ft_PCL_user_defined ||
1042 font->FontType == ft_GL2_stick_user_defined ||
1043 font->FontType == ft_MicroType ||
1044 font->FontType == ft_GL2_531) &&
1045 (i > 0 || !pdev->charproc_just_accumulated) &&
1046 !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))){
1047 code = gs_error_undefined;
1048 }
1049 else {
1050 if (font->FontType == ft_PCL_user_defined) {
1051 /* Check the cache, if the glyph has been flushed, assume that
1052 * it has been redefined, and do not use the current glyph.
1053 * Additional code in pdf_text_process will also spot this
1054 * condition and will not capture the glyph in this font.
1055 */
1056 /* Cache checking code copied from gxchar.c, show_proceed,
1057 * case 0, 'plain char'.
1058 */
1059 gs_font *rfont = (pte->fstack.depth < 0 ? pte->current_font : pte->fstack.items[0].font);
1060 gs_font *pfont = (pte->fstack.depth < 0 ? pte->current_font :
1061 pte->fstack.items[pte->fstack.depth].font);
1062 int wmode = rfont->WMode;
1063 gs_log2_scale_point log2_scale = {0,0};
1064 gs_fixed_point subpix_origin = {0,0};
1065 cached_fm_pair *pair;
1066
1067 code = gx_lookup_fm_pair(pfont, &ctm_only(pte->pgs), &log2_scale,
1068 false, &pair);
1069 if (code < 0)
1070 return code;
1071 if (gx_lookup_cached_char(pfont, pair, ch, wmode,
1072 1, &subpix_origin) == 0) {
1073 /* Character is not in cache, must have been redefined. */
1074 code = gs_error_undefined;
1075 }
1076 else {
1077 /* Character is in cache, go ahead and use it */
1078 code = pdf_char_widths((gx_device_pdf *)pte->dev,
1079 ppts->values.pdfont, ch, font, &cw);
1080 }
1081 } else
1082 /* Not a PCL bitmap font, we don't need to worry about redefined glyphs */
1083 code = pdf_char_widths((gx_device_pdf *)pte->dev,
1084 ppts->values.pdfont, ch, font, &cw);
1085 }
1086 if (code < 0) {
1087 if (i)
1088 break;
1089 *accepted = 0;
1090 return code;
1091 }
1092 pdf_char_widths_to_uts(pdfont, &cw);
1093 w.x += cw.real_width.xy.x;
1094 w.y += cw.real_width.xy.y;
1095 if (cw.real_width.xy.x != cw.Width.xy.x ||
1096 cw.real_width.xy.y != cw.Width.xy.y
1097 )
1098 widths_differ = 1;
1099 if (pstr->data[i] == space_char)
1100 ++num_spaces;
1101 if (cw.BBox.p.x != 0 && cw.BBox.q.x != 0){
1102 if (cw.BBox.p.x < bbox->p.x)
1103 bbox->p.x = cw.BBox.p.x;
1104 if (cw.BBox.p.y < bbox->p.y)
1105 bbox->p.y = cw.BBox.p.y;
1106 if (cw.BBox.q.x > bbox->q.x)
1107 bbox->q.x = cw.BBox.q.x;
1108 if (cw.BBox.q.y > bbox->q.y)
1109 bbox->q.y = cw.BBox.q.y;
1110 }
1111 }
1112 *accepted = i;
1113 gs_distance_transform(w.x * ppts->values.size, w.y * ppts->values.size,
1114 &ppts->values.matrix, &dpt);
1115 if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
1116 int num_chars = *accepted;
1117 gs_point tpt;
1118
1119 gs_distance_transform(pte->text.delta_all.x, pte->text.delta_all.y,
1120 &ctm_only(pte->pgs), &tpt);
1121 dpt.x += tpt.x * num_chars;
1122 dpt.y += tpt.y * num_chars;
1123 }
1124 if (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) {
1125 gs_point tpt;
1126
1127 gs_distance_transform(pte->text.delta_space.x, pte->text.delta_space.y,
1128 &ctm_only(pte->pgs), &tpt);
1129 dpt.x += tpt.x * num_spaces;
1130 dpt.y += tpt.y * num_spaces;
1131 }
1132 *pdpt = dpt;
1133
1134 return widths_differ;
1135 }
1136
1137 /*
1138 * Emulate TEXT_ADD_TO_ALL_WIDTHS and/or TEXT_ADD_TO_SPACE_WIDTH,
1139 * and implement TEXT_REPLACE_WIDTHS if requested.
1140 * Uses and updates ppts->values.matrix; uses ppts->values.pdfont.
1141 *
1142 * Destroys the text parameters in *pte.
1143 * The caller must restore them.
1144 */
1145 int
process_text_modify_width(pdf_text_enum_t * pte,gs_font * font,pdf_text_process_state_t * ppts,const gs_const_string * pstr,gs_point * pdpt,const gs_glyph * gdata,bool composite,int decoded_bytes)1146 process_text_modify_width(pdf_text_enum_t *pte, gs_font *font,
1147 pdf_text_process_state_t *ppts,
1148 const gs_const_string *pstr,
1149 gs_point *pdpt, const gs_glyph *gdata, bool composite, int decoded_bytes)
1150 {
1151 gx_device_pdf *const pdev = (gx_device_pdf *)pte->dev;
1152 int space_char =
1153 (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ?
1154 pte->text.space.s_char : -1);
1155 gs_point start, total;
1156 pdf_font_resource_t *pdfont3 = NULL;
1157 int code;
1158
1159 if (font->FontType == ft_user_defined ||
1160 font->FontType == ft_PDF_user_defined ||
1161 font->FontType == ft_PCL_user_defined ||
1162 font->FontType == ft_MicroType ||
1163 font->FontType == ft_GL2_stick_user_defined ||
1164 font->FontType == ft_GL2_531) {
1165 code = pdf_attached_font_resource(pdev, font, &pdfont3, NULL, NULL, NULL, NULL);
1166 if (code < 0)
1167 return code;
1168
1169 }
1170 pte->text.data.bytes = pstr->data;
1171 pte->text.size = pstr->size;
1172 pte->index = 0;
1173 pte->text.operation &= ~TEXT_FROM_ANY;
1174 pte->text.operation |= TEXT_FROM_STRING;
1175 start.x = ppts->values.matrix.tx;
1176 start.y = ppts->values.matrix.ty;
1177 total.x = total.y = 0; /* user space */
1178 /*
1179 * Note that character widths are in design space, but text.delta_*
1180 * values and the width value returned in *pdpt are in user space,
1181 * and the width values for pdf_append_chars are in device space.
1182 */
1183 for (;;) {
1184 pdf_glyph_widths_t cw; /* design space, then converted to PDF text space */
1185 gs_point did, wanted, tpt; /* user space */
1186 gs_point v = {0, 0}; /* design space */
1187 gs_char chr;
1188 gs_glyph glyph;
1189 int index = pte->index;
1190 gs_text_enum_t pte1 = *(gs_text_enum_t *)pte;
1191 int FontType;
1192 bool use_cached_v = true;
1193 byte composite_type3_text[1];
1194
1195 code = pte1.orig_font->procs.next_char_glyph(&pte1, &chr, &glyph);
1196 if (code == 2) { /* end of string */
1197 gs_text_enum_copy_dynamic((gs_text_enum_t *)pte, &pte1, true);
1198 break;
1199 }
1200 if (code < 0)
1201 return code;
1202 if (composite) { /* from process_cmap_text */
1203 gs_font *subfont = pte1.fstack.items[pte1.fstack.depth].font;
1204
1205 if (subfont->FontType == ft_user_defined || subfont->FontType == ft_PDF_user_defined ) {
1206 pdf_font_resource_t *pdfont;
1207
1208 FontType = subfont->FontType;
1209 code = pdf_attached_font_resource(pdev, subfont,
1210 &pdfont, NULL, NULL, NULL, NULL);
1211 if (code < 0)
1212 return code;
1213 chr = pdf_find_glyph(pdfont, glyph);
1214 composite_type3_text[0] = (byte)chr;
1215 code = pdf_char_widths((gx_device_pdf *)pte->dev,
1216 ppts->values.pdfont, chr, (gs_font_base *)subfont,
1217 &cw);
1218 } else {
1219 pdf_font_resource_t *pdsubf = ppts->values.pdfont->u.type0.DescendantFont;
1220
1221 FontType = pdsubf->FontType;
1222 code = pdf_glyph_widths(pdsubf, font->WMode, glyph, subfont, &cw,
1223 pte->cdevproc_callout ? pte->cdevproc_result : NULL);
1224 }
1225 } else {/* must be a base font */
1226 const gs_glyph *gdata_i = (gdata != NULL ? gdata + pte->index : 0);
1227
1228 /* gdata is NULL when composite == true, or the text isn't a single byte. */
1229 code = pdf_encode_string_element(pdev, font, ppts->values.pdfont, chr, gdata_i);
1230 FontType = font->FontType;
1231 if (code >= 0) {
1232 if (chr == GS_NO_CHAR && glyph != GS_NO_GLYPH) {
1233 /* glyphshow, we have no char code. Bug 686988.*/
1234 code = pdf_glyph_widths(ppts->values.pdfont, font->WMode, glyph, font, &cw, NULL);
1235 use_cached_v = false; /* Since we have no chr and don't call pdf_char_widths. */
1236 } else {
1237 code = pdf_char_widths((gx_device_pdf *)pte->dev,
1238 ppts->values.pdfont, chr, (gs_font_base *)font,
1239 &cw);
1240 if (code == 0 && font->FontType == ft_PCL_user_defined) {
1241 /* Check the cache, if the glyph has been flushed, assume that
1242 * it has been redefined, and do not use the current glyph.
1243 * Additional code in pdf_text_process will also spot this
1244 * condition and will not capture the glyph in this font.
1245 */
1246 /* Cache checking code copied from gxchar.c, show_proceed,
1247 * case 0, 'plain char'.
1248 */
1249 gs_font *rfont = (pte->fstack.depth < 0 ? pte->current_font : pte->fstack.items[0].font);
1250 gs_font *pfont = (pte->fstack.depth < 0 ? pte->current_font :
1251 pte->fstack.items[pte->fstack.depth].font);
1252 int wmode = rfont->WMode;
1253 gs_log2_scale_point log2_scale = {0,0};
1254 gs_fixed_point subpix_origin = {0,0};
1255 cached_fm_pair *pair;
1256
1257 code = gx_lookup_fm_pair(pfont, &ctm_only(pte->pgs), &log2_scale,
1258 false, &pair);
1259 if (code < 0)
1260 return code;
1261 if (gx_lookup_cached_char(pfont, pair, chr, wmode,
1262 1, &subpix_origin) == 0) {
1263 /* Character is not in cache, must have been redefined. */
1264 code = gs_error_undefined;
1265 }
1266 }
1267 }
1268 }
1269 }
1270 if (code < 0) {
1271 if (index > 0)
1272 break;
1273 return code;
1274 }
1275 /* TrueType design grid is 2048x2048 against the nominal PS/PDF grid of
1276 * 1000x1000. This can lead to rounding errors when converting to text space
1277 * and comparing against any entries in /W or /Widths arrays. We fix the
1278 * TrueType widths to the nearest integer here to avoid this.
1279 * See Bug #693825
1280 */
1281 if (FontType == ft_CID_TrueType || FontType == ft_TrueType) {
1282 cw.Width.w = floor(cw.Width.w + 0.5);
1283 cw.Width.xy.x = floor(cw.Width.xy.x + 0.5);
1284 cw.Width.xy.y = floor(cw.Width.xy.y + 0.5);
1285 cw.Width.v.x = floor(cw.Width.v.x + 0.5);
1286 cw.Width.v.y = floor(cw.Width.v.y + 0.5);
1287 cw.real_width.w = floor(cw.real_width.w + 0.5);
1288 cw.real_width.xy.x = floor(cw.real_width.xy.x + 0.5);
1289 cw.real_width.xy.y = floor(cw.real_width.xy.y + 0.5);
1290 cw.real_width.v.x = floor(cw.real_width.v.x + 0.5);
1291 cw.real_width.v.y = floor(cw.real_width.v.y + 0.5);
1292 }
1293
1294 gs_text_enum_copy_dynamic((gs_text_enum_t *)pte, &pte1, true);
1295 if (composite || !use_cached_v) {
1296 if (cw.replaced_v) {
1297 v.x = cw.real_width.v.x - cw.Width.v.x;
1298 v.y = cw.real_width.v.y - cw.Width.v.y;
1299 }
1300 } else
1301 v = ppts->values.pdfont->u.simple.v[chr];
1302 if (font->WMode && !cw.ignore_wmode) {
1303 /* With WMode 1 v-vector is (WMode 1 origin) - (WMode 0 origin).
1304 The glyph shifts in the opposite direction. */
1305 v.x = - v.x;
1306 v.y = - v.y;
1307 } else {
1308 /* With WMode 0 v-vector is (Metrics sb) - (native sb).
1309 The glyph shifts in same direction. */
1310 }
1311 /* pdf_glyph_origin is not longer used. */
1312 if (v.x != 0 || v.y != 0) {
1313 gs_point glyph_origin_shift;
1314 double scale0;
1315
1316 if (FontType == ft_TrueType || FontType == ft_CID_TrueType)
1317 scale0 = (float)0.001;
1318 else
1319 scale0 = 1;
1320 glyph_origin_shift.x = v.x * scale0;
1321 glyph_origin_shift.y = v.y * scale0;
1322 if (composite) {
1323 gs_font *subfont = pte->fstack.items[pte->fstack.depth].font;
1324
1325 gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y,
1326 &subfont->FontMatrix, &glyph_origin_shift);
1327 }
1328 gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y,
1329 &font->FontMatrix, &glyph_origin_shift);
1330 gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y,
1331 &ctm_only(pte->pgs), &glyph_origin_shift);
1332 if (glyph_origin_shift.x != 0 || glyph_origin_shift.y != 0) {
1333 ppts->values.matrix.tx = start.x + total.x + glyph_origin_shift.x;
1334 ppts->values.matrix.ty = start.y + total.y + glyph_origin_shift.y;
1335 code = pdf_set_text_state_values(pdev, &ppts->values);
1336 if (code < 0)
1337 break;
1338 }
1339 }
1340 pdf_char_widths_to_uts(pdfont3, &cw); /* convert design->text space */
1341 if (pte->text.operation & (TEXT_DO_DRAW | TEXT_RENDER_MODE_3)) {
1342 gs_distance_transform(cw.Width.xy.x * ppts->values.size,
1343 cw.Width.xy.y * ppts->values.size,
1344 &ppts->values.matrix, &did);
1345 gs_distance_transform(((font->WMode && !cw.ignore_wmode) ? 0 : ppts->values.character_spacing),
1346 ((font->WMode && !cw.ignore_wmode) ? ppts->values.character_spacing : 0),
1347 &ppts->values.matrix, &tpt);
1348 did.x += tpt.x;
1349 did.y += tpt.y;
1350 /* If pte->single_byte_space == 0 then we had a widthshow or awidthshow from
1351 * PostScript, so we apply the PostScript rules. Otherwise it was from PDF
1352 * in which case if the number of bytes in the character code was 1 we apply
1353 * word spacing. If it was PDF and we had a multi-byte decode, do not apply
1354 * word spacing (how ugly!). Note tht its important this is applied the same to
1355 * both the 'did' and 'wanted' calculations (see below).
1356 */
1357 if (chr == space_char && (!pte->single_byte_space || decoded_bytes == 1)) {
1358 gs_distance_transform(((font->WMode && !cw.ignore_wmode)? 0 : ppts->values.word_spacing),
1359 ((font->WMode && !cw.ignore_wmode) ? ppts->values.word_spacing : 0),
1360 &ppts->values.matrix, &tpt);
1361 did.x += tpt.x;
1362 did.y += tpt.y;
1363 }
1364 if (composite && (FontType == ft_user_defined || FontType == ft_PDF_user_defined))
1365 code = pdf_append_chars(pdev, composite_type3_text, 1, did.x, did.y, composite);
1366 else
1367 code = pdf_append_chars(pdev, pstr->data + index, pte->index - index, did.x, did.y, composite);
1368 if (code < 0)
1369 break;
1370 } else
1371 did.x = did.y = 0;
1372 if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
1373 gs_point dpt;
1374
1375 /* We are applying a width override, from x/y/xyshow. This coudl be from
1376 * a PostScript file, or it could be from a PDF file where we have a font
1377 * with a FontMatrix which is neither horizontal nor vertical. If we use TJ
1378 * for that, then we end up applying the displacement twice, once here where
1379 * we add a TJ, and once when we actually draw the glyph (TJ is added *after*
1380 * the glyph is drawn, unlike xshow). So in this case we don't want to try
1381 * and use a TJ, we need to position the glyphs using text positioning
1382 * operators.
1383 */
1384 if(cw.Width.xy.x != cw.real_width.xy.x || cw.Width.xy.y != cw.real_width.xy.y)
1385 pdev->text->text_state->can_use_TJ = false;
1386
1387 code = gs_text_replaced_width(&pte->text, pte->xy_index++, &dpt);
1388 if (code < 0)
1389 return_error(gs_error_unregistered);
1390 gs_distance_transform(dpt.x, dpt.y, &ctm_only(pte->pgs), &wanted);
1391 } else {
1392 pdev->text->text_state->can_use_TJ = true;
1393 gs_distance_transform(cw.real_width.xy.x * ppts->values.size,
1394 cw.real_width.xy.y * ppts->values.size,
1395 &ppts->values.matrix, &wanted);
1396 if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
1397 gs_distance_transform(pte->text.delta_all.x,
1398 pte->text.delta_all.y,
1399 &ctm_only(pte->pgs), &tpt);
1400 wanted.x += tpt.x;
1401 wanted.y += tpt.y;
1402 }
1403 /* See comment above for 'did' calculations, the application of word spacing must
1404 * be the same for did and wanted.
1405 */
1406 if (chr == space_char && (!pte->single_byte_space || decoded_bytes == 1)) {
1407 gs_distance_transform(pte->text.delta_space.x,
1408 pte->text.delta_space.y,
1409 &ctm_only(pte->pgs), &tpt);
1410 wanted.x += tpt.x;
1411 wanted.y += tpt.y;
1412 }
1413 }
1414 total.x += wanted.x;
1415 total.y += wanted.y;
1416 if (wanted.x != did.x || wanted.y != did.y) {
1417 ppts->values.matrix.tx = start.x + total.x;
1418 ppts->values.matrix.ty = start.y + total.y;
1419 code = pdf_set_text_state_values(pdev, &ppts->values);
1420 if (code < 0)
1421 break;
1422 }
1423 pdev->charproc_just_accumulated = false;
1424 }
1425 *pdpt = total;
1426 return 0;
1427 }
1428
1429 /*
1430 * Get character code from a glyph code.
1431 * An usage of this function is very undesirable,
1432 * because a glyph may be unlisted in Encoding.
1433 */
1434 int
pdf_encode_glyph(gs_font_base * bfont,gs_glyph glyph0,byte * buf,int buf_size,int * char_code_length)1435 pdf_encode_glyph(gs_font_base *bfont, gs_glyph glyph0,
1436 byte *buf, int buf_size, int *char_code_length)
1437 {
1438 gs_char c;
1439
1440 *char_code_length = 1;
1441 if (*char_code_length > buf_size)
1442 return_error(gs_error_rangecheck); /* Must not happen. */
1443 for (c = 0; c < 255; c++) {
1444 gs_glyph glyph1 = bfont->procs.encode_char((gs_font *)bfont, c,
1445 GLYPH_SPACE_NAME);
1446 if (glyph1 == glyph0) {
1447 buf[0] = (byte)c;
1448 return 0;
1449 }
1450 }
1451 return_error(gs_error_rangecheck); /* Can't encode. */
1452 }
1453
1454 /* ---------------- Type 1 or TrueType font ---------------- */
1455
1456 /*
1457 * Process a text string in a simple font.
1458 */
1459 int
process_plain_text(gs_text_enum_t * pte,void * vbuf,uint bsize)1460 process_plain_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
1461 {
1462 byte *const buf = vbuf;
1463 uint count;
1464 uint operation = pte->text.operation;
1465 pdf_text_enum_t *penum = (pdf_text_enum_t *)pte;
1466 int code;
1467 gs_string str;
1468 pdf_text_process_state_t text_state;
1469 const gs_glyph *gdata = NULL;
1470
1471 if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) {
1472 count = pte->text.size - pte->index;
1473 if (bsize < count)
1474 return_error(gs_error_unregistered); /* Must not happen. */
1475 memcpy(buf, (const byte *)pte->text.data.bytes + pte->index, count);
1476 } else if (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR)) {
1477 /* Check that all chars fit in a single byte. */
1478 const gs_char *cdata;
1479 int i;
1480
1481 if (operation & TEXT_FROM_CHARS) {
1482 cdata = pte->text.data.chars;
1483 count = (pte->text.size - pte->index);
1484 } else {
1485 cdata = &pte->text.data.d_char;
1486 count = 1;
1487 }
1488 if (bsize < count * sizeof(gs_char))
1489 return_error(gs_error_unregistered); /* Must not happen. */
1490 for (i = 0; i < count; ++i) {
1491 gs_char chr = cdata[pte->index + i];
1492
1493 if (chr & ~0xff)
1494 return_error(gs_error_rangecheck);
1495 buf[i] = (byte)chr;
1496 }
1497 } else if (operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH)) {
1498 /*
1499 * Since PDF has no analogue of 'glyphshow',
1500 * we try to encode glyphs with the current
1501 * font's encoding. If the current font has no encoding,
1502 * or the encoding doesn't contain necessary glyphs,
1503 * the text will be represented with a Type 3 font with
1504 * bitmaps or outlines.
1505 *
1506 * When we fail with encoding (136-01.ps is an example),
1507 * we could locate a PDF font resource or create a new one
1508 * with same outlines and an appropriate encoding.
1509 * Also we could change .notdef entries in the
1510 * copied font (assuming that document designer didn't use
1511 * .notdef for a meanful printing).
1512 * fixme: Not implemented yet.
1513 */
1514 gs_font *font = pte->current_font;
1515 uint size;
1516 int i;
1517
1518 if (operation & TEXT_FROM_GLYPHS) {
1519 gdata = pte->text.data.glyphs;
1520 size = pte->text.size - pte->index;
1521 } else {
1522 gdata = &pte->text.data.d_glyph;
1523 size = 1;
1524 }
1525 if (!pdf_is_simple_font(font))
1526 return_error(gs_error_unregistered); /* Must not happen. */
1527 count = 0;
1528 for (i = 0; i < size; ++i) {
1529 pdf_font_resource_t *pdfont;
1530 gs_glyph glyph = gdata[pte->index + i];
1531 int char_code_length;
1532
1533 code = pdf_encode_glyph((gs_font_base *)font, glyph,
1534 buf + count, size - count, &char_code_length);
1535 if (code < 0)
1536 break;
1537 /* Even if we already have a glyph encoded at this position in the font
1538 * it may not be the *right* glyph. We effectively use the first byte of
1539 * the glyph name as the index when using glyphshow which means that
1540 * /o and /omicron would be encoded at the same index. So we need
1541 * to check the actual glyph to see if they are the same. To do
1542 * that we need the PDF font resource which is attached to the font (if any).
1543 * cf bugs #695259 and #695168
1544 */
1545 code = pdf_attached_font_resource((gx_device_pdf *)penum->dev, font,
1546 &pdfont, NULL, NULL, NULL, NULL);
1547 if (code >= 0 && pdfont && pdfont->u.simple.Encoding[*(buf + count)].glyph != glyph)
1548 /* the glyph doesn't match the glyph already encoded at this position.
1549 * Breaking out here will start a new PDF font resource in the code below.
1550 */
1551 break;
1552 count += char_code_length;
1553 if (operation & TEXT_INTERVENE)
1554 break; /* Just do one character. */
1555 }
1556 if (i < size) {
1557 pdf_font_resource_t *pdfont;
1558
1559 str.data = buf;
1560 str.size = size;
1561 code = pdf_obtain_font_resource_unencoded(penum, &str, &pdfont, gdata);
1562 if (code < 0) {
1563 /*
1564 * pdf_text_process will fall back
1565 * to default implementation.
1566 */
1567 return code;
1568 }
1569 count = size;
1570 }
1571 /* So far we will use TEXT_FROM_STRING instead
1572 TEXT_FROM_*_GLYPH*. Since we used a single
1573 byte encoding, the character index appears invariant
1574 during this substitution.
1575 */
1576 } else
1577 return_error(gs_error_rangecheck);
1578 str.data = buf;
1579 if (count > 1 && (operation & TEXT_INTERVENE)) {
1580 /* Just do one character. */
1581 str.size = 1;
1582 code = pdf_process_string_aux(penum, &str, gdata, NULL, &text_state);
1583 if (code >= 0) {
1584 pte->returned.current_char = buf[0];
1585 code = TEXT_PROCESS_INTERVENE;
1586 }
1587 } else {
1588 str.size = count;
1589 code = pdf_process_string_aux(penum, &str, gdata, NULL, &text_state);
1590 }
1591 return code;
1592 }
1593