xref: /plan9/sys/src/cmd/gs/src/gdevpdte.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2002-2004 artofcode LLC. All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevpdte.c,v 1.70 2005/03/03 13:15:55 igor Exp $ */
18 /* Encoding-based (Type 1/2/42) text processing for pdfwrite. */
19 
20 #include "math_.h"
21 #include "memory_.h"
22 #include "gx.h"
23 #include "gserrors.h"
24 #include "gsutil.h"
25 #include "gxfcmap.h"
26 #include "gxfcopy.h"
27 #include "gxfont.h"
28 #include "gxfont0.h"
29 #include "gxfont0c.h"
30 #include "gxpath.h"		/* for getting current point */
31 #include "gdevpsf.h"
32 #include "gdevpdfx.h"
33 #include "gdevpdfg.h"
34 #include "gdevpdtx.h"
35 #include "gdevpdtd.h"
36 #include "gdevpdtf.h"
37 #include "gdevpdts.h"
38 #include "gdevpdtt.h"
39 
40 private int pdf_char_widths(gx_device_pdf *const pdev,
41 			    pdf_font_resource_t *pdfont, int ch,
42 			    gs_font_base *font,
43 			    pdf_glyph_widths_t *pwidths /* may be NULL */);
44 private int pdf_encode_string(gx_device_pdf *pdev, pdf_text_enum_t *penum,
45 		  const gs_string *pstr, const gs_glyph *gdata,
46 		  pdf_font_resource_t **ppdfont);
47 private int pdf_process_string(pdf_text_enum_t *penum, gs_string *pstr,
48 			       pdf_font_resource_t *pdfont,
49 			       const gs_matrix *pfmat,
50 			       pdf_text_process_state_t *ppts);
51 
52 /*
53  * Encode and process a string with a simple gs_font.
54  */
55 int
pdf_encode_process_string(pdf_text_enum_t * penum,gs_string * pstr,const gs_glyph * gdata,const gs_matrix * pfmat,pdf_text_process_state_t * ppts)56 pdf_encode_process_string(pdf_text_enum_t *penum, gs_string *pstr,
57 			  const gs_glyph *gdata, const gs_matrix *pfmat,
58 			  pdf_text_process_state_t *ppts)
59 {
60     gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev;
61     pdf_font_resource_t *pdfont;
62     gs_font_base *font;
63     int code = 0;
64 
65     switch (penum->current_font->FontType) {
66     case ft_TrueType:
67     case ft_encrypted:
68     case ft_encrypted2:
69     case ft_user_defined:
70 	break;
71     default:
72 	return_error(gs_error_rangecheck);
73     }
74     font = (gs_font_base *)penum->current_font;
75 
76     code = pdf_encode_string(pdev, penum, pstr, gdata, &pdfont); /* Must not change penum. */
77     if (code < 0)
78 	return code;
79     return pdf_process_string(penum, pstr, pdfont, pfmat, ppts);
80 }
81 
82 /*
83  * Add char code pair to ToUnicode CMap,
84  * creating the CMap on neccessity.
85  */
86 int
pdf_add_ToUnicode(gx_device_pdf * pdev,gs_font * font,pdf_font_resource_t * pdfont,gs_glyph glyph,gs_char ch)87 pdf_add_ToUnicode(gx_device_pdf *pdev, gs_font *font, pdf_font_resource_t *pdfont,
88 		  gs_glyph glyph, gs_char ch)
89 {   int code;
90     gs_char unicode;
91 
92     if (glyph == GS_NO_GLYPH)
93 	return 0;
94     unicode = font->procs.decode_glyph((gs_font *)font, glyph);
95     if (unicode != GS_NO_CHAR) {
96 	if (pdfont->cmap_ToUnicode == NULL) {
97 	    uint num_codes = 256, key_size = 1;
98 
99 	    if (font->FontType == ft_CID_encrypted) {
100 		gs_font_cid0 *pfcid = (gs_font_cid0 *)font;
101 
102 		num_codes = pfcid->cidata.common.CIDCount;
103 		key_size = 2;
104 	    } else if (font->FontType == ft_CID_TrueType) {
105 #if 0
106 		gs_font_cid2 *pfcid = (gs_font_cid2 *)font;
107 
108 		num_codes = pfcid->cidata.common.CIDCount;
109 #else
110 		/* Since PScript5.dll creates GlyphNames2Unicode with character codes
111 		   instead CIDs, and with the WinCharSetFFFF-H2 CMap
112 		   character codes appears from the range 0-0xFFFF (Bug 687954),
113 		   we must use the maximal character code value for the ToUnicode
114 		   code count. */
115 		num_codes = 65536;
116 #endif
117 		key_size = 2;
118 	    }
119 	    code = gs_cmap_ToUnicode_alloc(pdev->pdf_memory, pdfont->rid, num_codes, key_size,
120 					    &pdfont->cmap_ToUnicode);
121 	    if (code < 0)
122 		return code;
123 	}
124 	if (pdfont->cmap_ToUnicode != NULL)
125 	    gs_cmap_ToUnicode_add_pair(pdfont->cmap_ToUnicode, ch, unicode);
126     }
127     return 0;
128 }
129 
130 /*
131  * If the current substream is a charproc, register a font used in it.
132  */
133 int
pdf_register_charproc_resource(gx_device_pdf * pdev,gs_id id,pdf_resource_type_t type)134 pdf_register_charproc_resource(gx_device_pdf *pdev, gs_id id, pdf_resource_type_t type)
135 {
136     if (pdev->font3 != 0) {
137 	pdf_font_resource_t *pdfont = (pdf_font_resource_t *)pdev->font3;
138 	pdf_resource_ref_t *used_resources = pdfont->u.simple.s.type3.used_resources;
139 	int i, used_resources_count = pdfont->u.simple.s.type3.used_resources_count;
140 	int used_resources_max = pdfont->u.simple.s.type3.used_resources_max;
141 
142 	for (i = 0; i < used_resources_count; i++)
143 	    if (used_resources[i].id == id && used_resources[i].type == type)
144 		return 0;
145 	if (used_resources_count >= used_resources_max) {
146 	    used_resources_max += 10;
147 	    used_resources = (pdf_resource_ref_t *)gs_alloc_bytes(pdev->pdf_memory,
148 			sizeof(pdf_resource_ref_t) * used_resources_max,
149 			"pdf_register_charproc_resource");
150 	    if (!used_resources)
151 		return_error(gs_error_VMerror);
152 	    if (used_resources_count) {
153 		memcpy(used_resources, pdfont->u.simple.s.type3.used_resources,
154 		    sizeof(pdf_resource_ref_t) * used_resources_count);
155 		gs_free_object(pdev->pdf_memory, pdfont->u.simple.s.type3.used_resources,
156 			"pdf_register_charproc_resource");
157 	    }
158 	    pdfont->u.simple.s.type3.used_resources = used_resources;
159 	    pdfont->u.simple.s.type3.used_resources_max = used_resources_max;
160 	}
161 	used_resources[used_resources_count].id = id;
162 	used_resources[used_resources_count].type = type;
163 	pdfont->u.simple.s.type3.used_resources_count = used_resources_count + 1;
164     }
165     return 0;
166 }
167 
168 /*
169  * Register charproc fonts with the page or substream.
170  */
171 int
pdf_used_charproc_resources(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)172 pdf_used_charproc_resources(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
173 {
174     if (pdfont->where_used & pdev->used_mask)
175 	return 0;
176     pdfont->where_used |= pdev->used_mask;
177     if (pdfont->FontType == ft_user_defined) {
178 	pdf_resource_ref_t *used_resources = pdfont->u.simple.s.type3.used_resources;
179 	int i, used_resources_count = pdfont->u.simple.s.type3.used_resources_count;
180 
181 	for (i = 0; i < used_resources_count; i++) {
182 	    pdf_resource_t *pres =
183 		    pdf_find_resource_by_resource_id(pdev,
184 			    used_resources[i].type, used_resources[i].id);
185 	    if (pres == NULL)
186 		return_error(gs_error_unregistered); /* Must not happen. */
187 	    pres->where_used |= pdev->used_mask;
188 	}
189     }
190     return 0;
191 }
192 
193 /*
194  * Given a text string and a simple gs_font, return a font resource suitable
195  * for the text string, possibly re-encoding the string.  This
196  * may involve creating a font resource and/or adding glyphs and/or Encoding
197  * entries to it.
198  *
199  * Sets *ppdfont.
200  */
201 private int
pdf_encode_string(gx_device_pdf * pdev,pdf_text_enum_t * penum,const gs_string * pstr,const gs_glyph * gdata,pdf_font_resource_t ** ppdfont)202 pdf_encode_string(gx_device_pdf *pdev, pdf_text_enum_t *penum,
203 		  const gs_string *pstr, const gs_glyph *gdata,
204 		  pdf_font_resource_t **ppdfont)
205 {
206     gs_font *font = (gs_font *)penum->current_font;
207     pdf_font_resource_t *pdfont = 0;
208     gs_font_base *cfont, *ccfont;
209     int code, i;
210 
211     /*
212      * In contradiction with pre-7.20 versions of pdfwrite,
213      * we never re-encode texts due to possible encoding conflict while font merging.
214      */
215     code = pdf_obtain_font_resource(penum, pstr, &pdfont);
216     if (code < 0)
217 	return code;
218     code = pdf_add_resource(pdev, pdev->substream_Resources, "/Font", (pdf_resource_t *)pdfont);
219     if (code < 0)
220 	return code;
221     code = pdf_register_charproc_resource(pdev, pdf_resource_id((pdf_resource_t *)pdfont), resourceFont);
222     if (code < 0)
223 	return code;
224     cfont = pdf_font_resource_font(pdfont, false);
225     ccfont = pdf_font_resource_font(pdfont, true);
226     for (i = 0; i < pstr->size; ++i) {
227 	int ch = pstr->data[i];
228 	pdf_encoding_element_t *pet = &pdfont->u.simple.Encoding[ch];
229 	gs_glyph glyph = (gdata == NULL
230 			    ? font->procs.encode_char(font, ch, GLYPH_SPACE_NAME)
231 			    : gdata[i]);
232 
233 	gs_glyph copied_glyph;
234 	gs_const_string gnstr;
235 
236 	if (glyph == GS_NO_GLYPH || glyph == pet->glyph)
237 	    continue;
238 	if (pet->glyph != GS_NO_GLYPH) { /* encoding conflict */
239 	    return_error(gs_error_rangecheck);
240 	    /* Must not happen because pdf_obtain_font_resource
241 	     * checks for encoding compatibility.
242 	     */
243 	}
244 	code = font->procs.glyph_name(font, glyph, &gnstr);
245 	if (code < 0)
246 	    return code;	/* can't get name of glyph */
247 	if (font->FontType != ft_user_defined) {
248 	    /* The standard 14 fonts don't have a FontDescriptor. */
249 	    code = (pdfont->base_font != 0 ?
250 		    pdf_base_font_copy_glyph(pdfont->base_font, glyph, (gs_font_base *)font) :
251 		    pdf_font_used_glyph(pdfont->FontDescriptor, glyph, (gs_font_base *)font));
252 	    if (code < 0 && code != gs_error_undefined)
253 		return code;
254 	    if (code == gs_error_undefined) {
255 		/* PS font has no such glyph. */
256 		if (bytes_compare(gnstr.data, gnstr.size, (const byte *)".notdef", 7)) {
257 		    pet->glyph = glyph;
258 		    pet->str = gnstr;
259 		    pet->is_difference = true;
260 		}
261 	    } else if (pdfont->base_font == NULL && ccfont != NULL &&
262 		    (gs_copy_glyph_options(font, glyph, (gs_font *)ccfont, COPY_GLYPH_NO_NEW) != 1 ||
263 		     gs_copied_font_add_encoding((gs_font *)ccfont, ch, glyph) < 0)) {
264 		/*
265 		 * The "complete" copy of the font appears incomplete
266 		 * due to incrementally added glyphs. Drop the "complete"
267 		 * copy now and continue with subset font only.
268 		 *
269 		 * Note that we need to add the glyph to the encoding of the
270 		 * "complete" font, because "PPI-ProPag 2.6.1.4 (archivePg)"
271 		 * creates multiple font copies with reduced encodings
272 		 * (we believe it is poorly designed),
273 		 * and we can merge the copies back to a single font (see Bug 686875).
274 		 * We also check whether the encoding is compatible.
275 		 * It must be compatible here due to the pdf_obtain_font_resource
276 		 * and ccfont logics, but we want to ensure for safety reason.
277 		 */
278 		ccfont = NULL;
279 		pdf_font_descriptor_drop_complete_font(pdfont->FontDescriptor);
280 	    }
281 	    /*
282 	     * We arbitrarily allow the first encoded character in a given
283 	     * position to determine the encoding associated with the copied
284 	     * font.
285 	     */
286 	    copied_glyph = cfont->procs.encode_char((gs_font *)cfont, ch,
287 						    GLYPH_SPACE_NAME);
288 	    if (glyph != copied_glyph &&
289 		gs_copied_font_add_encoding((gs_font *)cfont, ch, glyph) < 0
290 		)
291 		pet->is_difference = true;
292 	    pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
293 	}
294 	/*
295 	 * We always generate ToUnicode for simple fonts, because
296 	 * we can't detemine in advance, which glyphs the font actually uses.
297 	 * The decision about writing it out is deferred until pdf_write_font_resource.
298 	 */
299 	code = pdf_add_ToUnicode(pdev, font, pdfont, glyph, ch);
300 	if (code < 0)
301 	    return code;
302 	pet->glyph = glyph;
303 	pet->str = gnstr;
304     }
305     *ppdfont = pdfont;
306     return 0;
307 }
308 
309 /*
310  * Estimate text bbox.
311  */
312 private 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)313 process_text_estimate_bbox(pdf_text_enum_t *pte, gs_font_base *font,
314 			  const gs_const_string *pstr,
315 			  const gs_matrix *pfmat,
316 			  gs_rect *text_bbox, gs_point *pdpt)
317 {
318     int i;
319     int space_char =
320 	(pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ?
321 	 pte->text.space.s_char : -1);
322     int WMode = font->WMode;
323     int code = 0;
324     gs_point total = {0, 0};
325     gs_fixed_point origin;
326     gs_matrix m;
327     int xy_index = pte->xy_index;
328 
329     if (font->FontBBox.p.x == font->FontBBox.q.x ||
330 	font->FontBBox.p.y == font->FontBBox.q.y)
331 	return_error(gs_error_undefined);
332     code = gx_path_current_point(pte->path, &origin);
333     if (code < 0)
334 	return code;
335     m = ctm_only(pte->pis);
336     m.tx = fixed2float(origin.x);
337     m.ty = fixed2float(origin.y);
338     gs_matrix_multiply(pfmat, &m, &m);
339     for (i = 0; i < pstr->size; ++i) {
340 	byte c = pstr->data[i];
341 	gs_rect bbox;
342 	gs_point wanted, tpt, p0, p1, p2, p3;
343 	gs_glyph glyph = font->procs.encode_char((gs_font *)font, c,
344 					GLYPH_SPACE_NAME);
345 	gs_glyph_info_t info;
346 	int code = font->procs.glyph_info((gs_font *)font, glyph, NULL,
347 					    GLYPH_INFO_WIDTH0 << WMode,
348 					    &info);
349 
350 	if (code < 0)
351 	    return code;
352 	gs_point_transform(font->FontBBox.p.x, font->FontBBox.p.y, &m, &p0);
353 	gs_point_transform(font->FontBBox.p.x, font->FontBBox.q.y, &m, &p1);
354 	gs_point_transform(font->FontBBox.q.x, font->FontBBox.p.y, &m, &p2);
355 	gs_point_transform(font->FontBBox.q.x, font->FontBBox.q.y, &m, &p3);
356 	bbox.p.x = min(min(p0.x, p1.x), min(p1.x, p2.x)) + total.x;
357 	bbox.p.y = min(min(p0.y, p1.y), min(p1.y, p2.y)) + total.y;
358 	bbox.q.x = max(max(p0.x, p1.x), max(p1.x, p2.x)) + total.x;
359 	bbox.q.y = max(max(p0.y, p1.y), max(p1.y, p2.y)) + total.y;
360 	if (i == 0)
361 	    *text_bbox = bbox;
362 	else
363 	    rect_merge(*text_bbox, bbox);
364 	if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
365 	    gs_text_replaced_width(&pte->text, xy_index++, &tpt);
366 	    gs_distance_transform(tpt.x, tpt.y, &ctm_only(pte->pis), &wanted);
367 	} else {
368 	    gs_distance_transform(info.width[WMode].x,
369 				  info.width[WMode].y,
370 				  &m, &wanted);
371 	    if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
372 		gs_distance_transform(pte->text.delta_all.x,
373 				      pte->text.delta_all.y,
374 				      &ctm_only(pte->pis), &tpt);
375 		wanted.x += tpt.x;
376 		wanted.y += tpt.y;
377 	    }
378 	    if (pstr->data[i] == space_char && pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) {
379 		gs_distance_transform(pte->text.delta_space.x,
380 				      pte->text.delta_space.y,
381 				      &ctm_only(pte->pis), &tpt);
382 		wanted.x += tpt.x;
383 		wanted.y += tpt.y;
384 	    }
385 	}
386 	total.x += wanted.x;
387 	total.y += wanted.y;
388     }
389     *pdpt = total;
390     return 0;
391 }
392 
393 private void
adjust_first_last_char(pdf_font_resource_t * pdfont,byte * str,int size)394 adjust_first_last_char(pdf_font_resource_t *pdfont, byte *str, int size)
395 {
396     int i;
397 
398     for (i = 0; i < size; ++i) {
399 	int chr = str[i];
400 
401 	if (chr < pdfont->u.simple.FirstChar)
402 	    pdfont->u.simple.FirstChar = chr;
403 	if (chr > pdfont->u.simple.LastChar)
404 	    pdfont->u.simple.LastChar = chr;
405     }
406 }
407 
408 int
pdf_shift_text_currentpoint(pdf_text_enum_t * penum,gs_point * wpt)409 pdf_shift_text_currentpoint(pdf_text_enum_t *penum, gs_point *wpt)
410 {
411     gs_state *pgs;
412     extern_st(st_gs_state);
413 
414     if (gs_object_type(penum->dev->memory, penum->pis) != &st_gs_state) {
415 	/* Probably never happens. Not sure though. */
416 	return_error(gs_error_unregistered);
417     }
418     pgs = (gs_state *)penum->pis;
419     return gs_moveto_aux(penum->pis, gx_current_path(pgs),
420 			      fixed2float(penum->origin.x) + wpt->x,
421 			      fixed2float(penum->origin.y) + wpt->y);
422 }
423 
424 /*
425  * Internal procedure to process a string in a non-composite font.
426  * Doesn't use or set pte->{data,size,index}; may use/set pte->xy_index;
427  * may set penum->returned.total_width.  Sets ppts->values.
428  *
429  * Note that the caller is responsible for re-encoding the string, if
430  * necessary; for adding Encoding entries in pdfont; and for copying any
431  * necessary glyphs.  penum->current_font provides the gs_font for getting
432  * glyph metrics, but this font's Encoding is not used.
433  */
434 private int process_text_return_width(const pdf_text_enum_t *pte,
435 				      gs_font_base *font,
436 				      pdf_text_process_state_t *ppts,
437 				      const gs_const_string *pstr,
438 				      gs_point *pdpt, int *accepted);
439 private int
pdf_process_string(pdf_text_enum_t * penum,gs_string * pstr,pdf_font_resource_t * pdfont,const gs_matrix * pfmat,pdf_text_process_state_t * ppts)440 pdf_process_string(pdf_text_enum_t *penum, gs_string *pstr,
441 		   pdf_font_resource_t *pdfont, const gs_matrix *pfmat,
442 		   pdf_text_process_state_t *ppts)
443 {
444     gx_device_pdf *const pdev = (gx_device_pdf *)penum->dev;
445     gs_font_base *font = (gs_font_base *)penum->current_font;
446     const gs_text_params_t *text = &penum->text;
447     int code = 0, mask;
448     gs_point width_pt;
449     gs_rect text_bbox;
450     int accepted;
451 
452     if (pfmat == 0)
453 	pfmat = &font->FontMatrix;
454     if (text->operation & TEXT_RETURN_WIDTH) {
455 	code = gx_path_current_point(penum->path, &penum->origin);
456 	if (code < 0)
457 	    return code;
458     }
459     if (text->size == 0)
460 	return 0;
461     if (penum->pis->text_rendering_mode != 3 && !(text->operation & TEXT_DO_NONE)) {
462 	/*
463 	 * Acrobat Reader can't handle text with huge coordinates,
464 	 * so skip the text if it is outside the clip bbox
465 	 * (Note : it ever fails with type 3 fonts).
466 	 */
467 	code = process_text_estimate_bbox(penum, font, (gs_const_string *)pstr, pfmat,
468 					  &text_bbox, &width_pt);
469 	if (code == 0) {
470 	    gs_fixed_rect clip_bbox;
471 	    gs_rect rect;
472 
473 	    gx_cpath_outer_box(penum->pcpath, &clip_bbox);
474 	    rect.p.x = fixed2float(clip_bbox.p.x);
475 	    rect.p.y = fixed2float(clip_bbox.p.y);
476 	    rect.q.x = fixed2float(clip_bbox.q.x);
477 	    rect.q.y = fixed2float(clip_bbox.q.y);
478 	    rect_intersect(rect, text_bbox);
479 	    if (rect.p.x > rect.q.x || rect.p.y > rect.q.y) {
480 		penum->index += pstr->size;
481 		goto finish;
482 	    }
483 	}
484     } else {
485 	/* We have no penum->pcpath. */
486     }
487 
488     /*
489      * Note that pdf_update_text_state sets all the members of ppts->values
490      * to their current values.
491      */
492     code = pdf_update_text_state(ppts, penum, pdfont, pfmat);
493     if (code > 0) {
494 	/* Try not to emulate ADD_TO_WIDTH if we don't have to. */
495 	if (code & TEXT_ADD_TO_SPACE_WIDTH) {
496 	    if (!memchr(pstr->data, penum->text.space.s_char, pstr->size))
497 		code &= ~TEXT_ADD_TO_SPACE_WIDTH;
498 	}
499     }
500     if (code < 0)
501 	return code;
502     mask = code;
503 
504     if (text->operation & TEXT_REPLACE_WIDTHS)
505 	mask |= TEXT_REPLACE_WIDTHS;
506 
507     /*
508      * The only operations left to handle are TEXT_DO_DRAW and
509      * TEXT_RETURN_WIDTH.
510      */
511     if (mask == 0) {
512 	/*
513 	 * If any character has real_width != Width, we have to process
514 	 * the string character-by-character.  process_text_return_width
515 	 * will tell us what we need to know.
516 	 */
517 	if (!(text->operation & (TEXT_DO_DRAW | TEXT_RETURN_WIDTH)))
518 	    return 0;
519 	code = process_text_return_width(penum, font, ppts,
520 					 (gs_const_string *)pstr,
521 					 &width_pt, &accepted);
522 	if (code < 0)
523 	    return code;
524 	if (code == 0) {
525 	    /* No characters with redefined widths -- the fast case. */
526 	    if (text->operation & TEXT_DO_DRAW || penum->pis->text_rendering_mode == 3) {
527 		code = pdf_append_chars(pdev, pstr->data, accepted,
528 					width_pt.x, width_pt.y, false);
529 		if (code < 0)
530 		    return code;
531 		adjust_first_last_char(pdfont, pstr->data, accepted);
532 		penum->index += accepted;
533 	    } else if (text->operation & TEXT_DO_NONE)
534 		penum->index += accepted;
535 	} else {
536 	    /* Use the slow case.  Set mask to any non-zero value. */
537 	    mask = TEXT_RETURN_WIDTH;
538 	}
539     }
540     if (mask) {
541 	/* process_text_modify_width destroys text parameters, save them now. */
542         int index0 = penum->index, xy_index = penum->xy_index;
543 	gs_text_params_t text = penum->text;
544 	int xy_index_step = (penum->text.x_widths != NULL && /* see gs_text_replaced_width */
545 			     penum->text.x_widths == penum->text.y_widths ? 2 : 1);
546 
547 	if (penum->text.x_widths != NULL) {
548 	    penum->text.x_widths += xy_index * xy_index_step;
549 	}
550 	if (penum->text.y_widths != NULL)
551 	    penum->text.y_widths += xy_index * xy_index_step;
552 	penum->xy_index = 0;
553 	code = process_text_modify_width(penum, (gs_font *)font, ppts,
554 					 (gs_const_string *)pstr,
555 					 &width_pt);
556 	if (penum->text.x_widths != NULL)
557 	    penum->text.x_widths -= xy_index * xy_index_step;
558 	if (penum->text.y_widths != NULL)
559 	    penum->text.y_widths -= xy_index * xy_index_step;
560 	penum->xy_index += xy_index;
561 	adjust_first_last_char(pdfont, pstr->data, penum->index);
562 	penum->text = text;
563 	penum->index += index0;
564 	if (code < 0)
565 	    return code;
566     }
567 
568 
569 finish:
570     /* Finally, return the total width if requested. */
571     if (!(text->operation & TEXT_RETURN_WIDTH))
572 	return 0;
573     if (text->operation & TEXT_DO_NONE) {
574 	/* stringwidth needs to transform to user space. */
575 	gs_point p;
576 
577 	gs_distance_transform_inverse(width_pt.x, width_pt.y, &ctm_only(penum->pis), &p);
578 	penum->returned.total_width.x += p.x;
579 	penum->returned.total_width.y += p.y;
580     } else
581 	penum->returned.total_width = width_pt;
582     return pdf_shift_text_currentpoint(penum, &width_pt);
583 }
584 
585 /*
586  * Get the widths (unmodified and possibly modified) of a given character
587  * in a simple font.  May add the widths to the widths cache (pdfont->Widths
588  * and pdf_font_cache_elem::real_widths).  Return 1 if the widths were not cached.
589  */
590 private 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)591 pdf_char_widths(gx_device_pdf *const pdev,
592 		pdf_font_resource_t *pdfont, int ch, gs_font_base *font,
593 		pdf_glyph_widths_t *pwidths /* may be NULL */)
594 {
595     pdf_glyph_widths_t widths;
596     int code;
597     byte *glyph_usage;
598     double *real_widths;
599     int char_cache_size, width_cache_size;
600     pdf_font_resource_t *pdfont1;
601 
602     code = pdf_attached_font_resource(pdev, (gs_font *)font, &pdfont1,
603 				&glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
604     if (code < 0)
605 	return code;
606     if (pdfont1 != pdfont)
607 	return_error(gs_error_unregistered); /* Must not happen. */
608     if (ch < 0 || ch > 255)
609 	return_error(gs_error_rangecheck);
610     if (ch >= width_cache_size)
611 	return_error(gs_error_unregistered); /* Must not happen. */
612     if (pwidths == 0)
613 	pwidths = &widths;
614     if (font->FontType != ft_user_defined && real_widths[ch] == 0) {
615 	/* Might be an unused char, or just not cached. */
616 	gs_glyph glyph = pdfont->u.simple.Encoding[ch].glyph;
617 
618 	code = pdf_glyph_widths(pdfont, font->WMode, glyph, (gs_font *)font, pwidths, NULL);
619 	if (code < 0)
620 	    return code;
621 	if (font->WMode != 0 && code > 0 && !pwidths->replaced_v) {
622 	    /*
623 	     * The font has no Metrics2, so it must write
624 	     * horizontally due to PS spec.
625 	     * Therefore we need to fill the Widths array,
626 	     * which is required by PDF spec.
627 	     * Take it from WMode==0.
628 	     */
629 	    code = pdf_glyph_widths(pdfont, 0, glyph, (gs_font *)font, pwidths, NULL);
630 	}
631 	if (pwidths->replaced_v) {
632 	    pdfont->u.simple.v[ch].x = pwidths->real_width.v.x - pwidths->Width.v.x;
633 	    pdfont->u.simple.v[ch].y = pwidths->real_width.v.y - pwidths->Width.v.y;
634 	} else
635 	    pdfont->u.simple.v[ch].x = pdfont->u.simple.v[ch].y = 0;
636 	if (code == 0) {
637 	    pdfont->Widths[ch] = pwidths->Width.w;
638 	    real_widths[ch] = pwidths->real_width.w;
639 	}
640     } else {
641 	if (font->FontType == ft_user_defined) {
642 	    if (!(pdfont->used[ch >> 3] & 0x80 >> (ch & 7)))
643 		return gs_error_undefined; /* The charproc was not accumulated. */
644 	    if (!pdev->charproc_just_accumulated &&
645 		!(pdfont->u.simple.s.type3.cached[ch >> 3] & 0x80 >> (ch & 7))) {
646 		 /* The charproc uses setcharwidth.
647 		    Need to accumulate again to check for a glyph variation. */
648 		return gs_error_undefined;
649 	    }
650 	}
651 	pwidths->Width.w = pdfont->Widths[ch];
652 	pwidths->Width.v = pdfont->u.simple.v[ch];
653 	if (font->FontType == ft_user_defined) {
654 	    pwidths->real_width.w = real_widths[ch * 2];
655 	    pwidths->Width.xy.x = pwidths->Width.w;
656 	    pwidths->Width.xy.y = 0;
657 	    pwidths->real_width.xy.x = real_widths[ch * 2 + 0];
658 	    pwidths->real_width.xy.y = real_widths[ch * 2 + 1];
659 	} else if (font->WMode) {
660 	    pwidths->real_width.w = real_widths[ch];
661 	    pwidths->Width.xy.x = 0;
662 	    pwidths->Width.xy.y = pwidths->Width.w;
663 	    pwidths->real_width.xy.x = 0;
664 	    pwidths->real_width.xy.y = pwidths->real_width.w;
665 	} else {
666 	    pwidths->real_width.w = real_widths[ch];
667 	    pwidths->Width.xy.x = pwidths->Width.w;
668 	    pwidths->Width.xy.y = 0;
669 	    pwidths->real_width.xy.x = pwidths->real_width.w;
670 	    pwidths->real_width.xy.y = 0;
671 	}
672 	code = 0;
673     }
674     return code;
675 }
676 
677 /*
678  * Compute the total text width (in user space).  Return 1 if any
679  * character had real_width != Width, otherwise 0.
680  */
681 private 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,gs_point * pdpt,int * accepted)682 process_text_return_width(const pdf_text_enum_t *pte, gs_font_base *font,
683 			  pdf_text_process_state_t *ppts,
684 			  const gs_const_string *pstr,
685 			  gs_point *pdpt, int *accepted)
686 {
687     int i;
688     gs_point w;
689     double scale;
690     gs_point dpt;
691     int num_spaces = 0;
692     int space_char =
693 	(pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ?
694 	 pte->text.space.s_char : -1);
695     int widths_differ = 0, code;
696     gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
697     pdf_font_resource_t *pdfont;
698 
699     code = pdf_attached_font_resource(pdev, (gs_font *)font, &pdfont, NULL, NULL, NULL, NULL);
700     if (code < 0)
701 	return code;
702     if (font->FontType == ft_user_defined) {
703 	pdf_font3_scale(pdev, (gs_font *)font, &scale);
704 	scale *= ppts->values.size;
705     } else
706 	scale = 0.001 * ppts->values.size;
707     for (i = 0, w.x = w.y = 0; i < pstr->size; ++i) {
708 	pdf_glyph_widths_t cw;
709 	gs_char ch = pstr->data[i];
710 
711 	if (font->FontType == ft_user_defined &&
712 	    (i > 0 || !pdev->charproc_just_accumulated) &&
713 	    !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7))))
714 	    code = gs_error_undefined;
715 	else
716 	    code = pdf_char_widths((gx_device_pdf *)pte->dev,
717 	                           ppts->values.pdfont, ch, font,
718 				   &cw);
719 	if (code < 0) {
720 	    if (i)
721 		break;
722 	    *accepted = 0;
723 	    return code;
724 	}
725 	w.x += cw.real_width.xy.x;
726 	w.y += cw.real_width.xy.y;
727 	if (cw.real_width.xy.x != cw.Width.xy.x ||
728 	    cw.real_width.xy.y != cw.Width.xy.y
729 	    )
730 	    widths_differ = 1;
731 	if (pstr->data[i] == space_char)
732 	    ++num_spaces;
733     }
734     *accepted = i;
735     gs_distance_transform(w.x * scale, w.y * scale,
736 			  &ppts->values.matrix, &dpt);
737     if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
738 	int num_chars = *accepted;
739 	gs_point tpt;
740 
741 	gs_distance_transform(pte->text.delta_all.x, pte->text.delta_all.y,
742 			      &ctm_only(pte->pis), &tpt);
743 	dpt.x += tpt.x * num_chars;
744 	dpt.y += tpt.y * num_chars;
745     }
746     if (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) {
747 	gs_point tpt;
748 
749 	gs_distance_transform(pte->text.delta_space.x, pte->text.delta_space.y,
750 			      &ctm_only(pte->pis), &tpt);
751 	dpt.x += tpt.x * num_spaces;
752 	dpt.y += tpt.y * num_spaces;
753     }
754     *pdpt = dpt;
755 
756     return widths_differ;
757 }
758 
759 #define RIGHT_SBW 1 /* Old code = 0, new code = 1. */
760 #if !RIGHT_SBW
761 /*
762  * Retrieve glyph origing shift for WMode = 1 in design units.
763  */
764 private void
pdf_glyph_origin(pdf_font_resource_t * pdfont,int ch,int WMode,gs_point * p)765 pdf_glyph_origin(pdf_font_resource_t *pdfont, int ch, int WMode, gs_point *p)
766 {
767     /* For CID fonts PDF viewers provide glyph origin shift automatically.
768      * Therefore we only need to do for non-CID fonts.
769      */
770     switch (pdfont->FontType) {
771 	case ft_encrypted:
772 	case ft_encrypted2:
773 	case ft_TrueType:
774 	case ft_user_defined:
775 	    *p = pdfont->u.simple.v[ch];
776 	    break;
777 	default:
778 	    p->x = p->y = 0;
779 	    break;
780     }
781 }
782 #endif
783 
784 /*
785  * Emulate TEXT_ADD_TO_ALL_WIDTHS and/or TEXT_ADD_TO_SPACE_WIDTH,
786  * and implement TEXT_REPLACE_WIDTHS if requested.
787  * Uses and updates ppts->values.matrix; uses ppts->values.pdfont.
788  *
789  * Destroys the text parameters in *pte.
790  * The caller must restore them.
791  */
792 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)793 process_text_modify_width(pdf_text_enum_t *pte, gs_font *font,
794 			  pdf_text_process_state_t *ppts,
795 			  const gs_const_string *pstr,
796 			  gs_point *pdpt)
797 {
798     gx_device_pdf *const pdev = (gx_device_pdf *)pte->dev;
799     double scale;
800     int space_char =
801 	(pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH ?
802 	 pte->text.space.s_char : -1);
803     int code = 0;
804     gs_point start, total;
805     bool composite = (ppts->values.pdfont->FontType == ft_composite);
806 
807     if (font->FontType == ft_user_defined) {
808 	gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
809 
810 	pdf_font3_scale(pdev, font, &scale);
811 	scale *= ppts->values.size;
812     } else
813 	scale = 0.001 * ppts->values.size;
814     pte->text.data.bytes = pstr->data;
815     pte->text.size = pstr->size;
816     pte->index = 0;
817     pte->text.operation &= ~TEXT_FROM_ANY;
818     pte->text.operation |= TEXT_FROM_STRING;
819     start.x = ppts->values.matrix.tx;
820     start.y = ppts->values.matrix.ty;
821     total.x = total.y = 0;	/* user space */
822     /*
823      * Note that character widths are in design space, but text.delta_*
824      * values and the width value returned in *pdpt are in user space,
825      * and the width values for pdf_append_chars are in device space.
826      */
827     for (;;) {
828 	pdf_glyph_widths_t cw;	/* design space */
829 	gs_point did, wanted, tpt;	/* user space */
830 	gs_point v = {0, 0}; /* design space */
831 	gs_char chr;
832 	gs_glyph glyph;
833 	int code, index = pte->index;
834 	gs_text_enum_t pte1 = *(gs_text_enum_t *)pte;
835 	int FontType;
836 #if RIGHT_SBW
837 	bool use_cached_v = true;
838 #endif
839 
840 	code = pte1.orig_font->procs.next_char_glyph(&pte1, &chr, &glyph);
841 	if (code == 2) { /* end of string */
842 	    gs_text_enum_copy_dynamic((gs_text_enum_t *)pte, &pte1, true);
843 	    break;
844 	}
845 	if (code < 0)
846 	    return code;
847 	if (composite) { /* from process_cmap_text */
848 	    gs_font *subfont = pte1.fstack.items[pte1.fstack.depth].font;
849 	    pdf_font_resource_t *pdsubf = ppts->values.pdfont->u.type0.DescendantFont;
850 
851 	    FontType = pdsubf->FontType;
852 	    code = pdf_glyph_widths(pdsubf, font->WMode, glyph, subfont, &cw,
853 		pte->cdevproc_callout ? pte->cdevproc_result : NULL);
854 	} else {/* must be a base font */
855 	    FontType = font->FontType;
856 	    if (chr == GS_NO_CHAR && glyph != GS_NO_GLYPH) {
857 		/* glyphshow, we have no char code. Bug 686988.*/
858 		code = pdf_glyph_widths(ppts->values.pdfont, font->WMode, glyph, font, &cw, NULL);
859 		use_cached_v = false; /* Since we have no chr and don't call pdf_char_widths. */
860 	    } else
861 		code = pdf_char_widths((gx_device_pdf *)pte->dev,
862 				       ppts->values.pdfont, chr, (gs_font_base *)font,
863 				       &cw);
864 	}
865 	if (code < 0) {
866 	    if (index > 0)
867 		break;
868 	    return code;
869 	}
870 	gs_text_enum_copy_dynamic((gs_text_enum_t *)pte, &pte1, true);
871 #if RIGHT_SBW
872 	if (composite || !use_cached_v) {
873 	    if (cw.replaced_v) {
874 		v.x = cw.real_width.v.x - cw.Width.v.x;
875 		v.y = cw.real_width.v.y - cw.Width.v.y;
876 	    }
877 	} else
878 	    v = ppts->values.pdfont->u.simple.v[chr];
879 	if (font->WMode) {
880 	    /* With WMode 1 v-vector is (WMode 1 origin) - (WMode 0 origin).
881 	       The glyph shifts in the opposite direction.  */
882 	    v.x = - v.x;
883 	    v.y = - v.y;
884 	} else {
885 	    /* With WMode 0 v-vector is (Metrics sb) - (native sb).
886 	       The glyph shifts in same direction.  */
887 	}
888 	/* pdf_glyph_origin is not longer used. */
889 #else
890 	if ((pte->text.operation & TEXT_FROM_SINGLE_GLYPH) ||
891 	    (pte->text.operation & TEXT_FROM_GLYPHS)) {
892 	    v.x = v.y = 0;
893 	} else if (composite) {
894 	    if (cw.replaced_v) {
895 		v.x = cw.real_width.v.x - cw.Width.v.x;
896 		v.y = cw.real_width.v.y - cw.Width.v.y;
897 	    }
898 	} else
899 	    pdf_glyph_origin(ppts->values.pdfont, chr, font->WMode, &v);
900 #endif
901 	if (v.x != 0 || v.y != 0) {
902 	    gs_point glyph_origin_shift;
903 	    double scale0;
904 
905 	    if (FontType == ft_TrueType || FontType == ft_CID_TrueType)
906 		scale0 = (float)0.001;
907 	    else
908 		scale0 = 1;
909 #if RIGHT_SBW
910 	    glyph_origin_shift.x = v.x * scale0;
911 	    glyph_origin_shift.y = v.y * scale0;
912 #else
913 	    glyph_origin_shift.x = - v.x * scale0;
914 	    glyph_origin_shift.y = - v.y * scale0;
915 #endif
916 	    if (composite) {
917 		gs_font *subfont = pte->fstack.items[pte->fstack.depth].font;
918 
919 		gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y,
920 				      &subfont->FontMatrix, &glyph_origin_shift);
921 	    }
922 	    gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y,
923 				  &font->FontMatrix, &glyph_origin_shift);
924 	    gs_distance_transform(glyph_origin_shift.x, glyph_origin_shift.y,
925 				  &ctm_only(pte->pis), &glyph_origin_shift);
926 	    if (glyph_origin_shift.x != 0 || glyph_origin_shift.y != 0) {
927 		ppts->values.matrix.tx = start.x + total.x + glyph_origin_shift.x;
928 		ppts->values.matrix.ty = start.y + total.y + glyph_origin_shift.y;
929 		code = pdf_set_text_state_values(pdev, &ppts->values);
930 		if (code < 0)
931 		    break;
932 	    }
933 	}
934 	if (pte->text.operation & TEXT_DO_DRAW) {
935 	    gs_distance_transform(cw.Width.xy.x * scale,
936 				  cw.Width.xy.y * scale,
937 				  &ppts->values.matrix, &did);
938 	    gs_distance_transform((font->WMode ? 0 : ppts->values.character_spacing),
939 				  (font->WMode ? ppts->values.character_spacing : 0),
940 				  &ppts->values.matrix, &tpt);
941 	    did.x += tpt.x;
942 	    did.y += tpt.y;
943 	    if (chr == space_char) {
944 		gs_distance_transform((font->WMode ? 0 : ppts->values.word_spacing),
945 				      (font->WMode ? ppts->values.word_spacing : 0),
946 				      &ppts->values.matrix, &tpt);
947 		did.x += tpt.x;
948 		did.y += tpt.y;
949 	    }
950 	    code = pdf_append_chars(pdev, pstr->data + index, pte->index - index, did.x, did.y, composite);
951 	    if (code < 0)
952 		break;
953 	} else
954 	    did.x = did.y = 0;
955 	if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
956 	    gs_point dpt;
957 
958 	    code = gs_text_replaced_width(&pte->text, pte->xy_index++, &dpt);
959 	    if (code < 0)
960 		return_error(gs_error_unregistered);
961 	    gs_distance_transform(dpt.x, dpt.y, &ctm_only(pte->pis), &wanted);
962 	} else {
963 	    gs_distance_transform(cw.real_width.xy.x * scale,
964 				  cw.real_width.xy.y * scale,
965 				  &ppts->values.matrix, &wanted);
966 	    if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
967 		gs_distance_transform(pte->text.delta_all.x,
968 				      pte->text.delta_all.y,
969 				      &ctm_only(pte->pis), &tpt);
970 		wanted.x += tpt.x;
971 		wanted.y += tpt.y;
972 	    }
973 	    if (chr == space_char && pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) {
974 		gs_distance_transform(pte->text.delta_space.x,
975 				      pte->text.delta_space.y,
976 				      &ctm_only(pte->pis), &tpt);
977 		wanted.x += tpt.x;
978 		wanted.y += tpt.y;
979 	    }
980 	}
981 	total.x += wanted.x;
982 	total.y += wanted.y;
983 	if (wanted.x != did.x || wanted.y != did.y) {
984 	    ppts->values.matrix.tx = start.x + total.x;
985 	    ppts->values.matrix.ty = start.y + total.y;
986 	    code = pdf_set_text_state_values(pdev, &ppts->values);
987 	    if (code < 0)
988 		break;
989 	}
990 	pdev->charproc_just_accumulated = false;
991     }
992     *pdpt = total;
993     return code;
994 }
995 
996 /*
997  * Get character code from a glyph code.
998  * An usage of this function is very undesirable,
999  * because a glyph may be unlisted in Encoding.
1000  */
1001 int
pdf_encode_glyph(gs_font_base * bfont,gs_glyph glyph0,byte * buf,int buf_size,int * char_code_length)1002 pdf_encode_glyph(gs_font_base *bfont, gs_glyph glyph0,
1003 	    byte *buf, int buf_size, int *char_code_length)
1004 {
1005     gs_char c;
1006 
1007     *char_code_length = 1;
1008     if (*char_code_length > buf_size)
1009 	return_error(gs_error_rangecheck); /* Must not happen. */
1010     for (c = 0; c < 255; c++) {
1011 	gs_glyph glyph1 = bfont->procs.encode_char((gs_font *)bfont, c,
1012 		    GLYPH_SPACE_NAME);
1013 	if (glyph1 == glyph0) {
1014 	    buf[0] = (byte)c;
1015 	    return 0;
1016 	}
1017     }
1018     return_error(gs_error_rangecheck); /* Can't encode. */
1019 }
1020 
1021 /* ---------------- Type 1 or TrueType font ---------------- */
1022 
1023 /*
1024  * Process a text string in a simple font.
1025  */
1026 int
process_plain_text(gs_text_enum_t * pte,void * vbuf,uint bsize)1027 process_plain_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
1028 {
1029     byte *const buf = vbuf;
1030     uint count;
1031     uint operation = pte->text.operation;
1032     pdf_text_enum_t *penum = (pdf_text_enum_t *)pte;
1033     int code;
1034     gs_string str;
1035     pdf_text_process_state_t text_state;
1036     const gs_glyph *gdata = NULL;
1037 
1038     if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) {
1039 	count = pte->text.size - pte->index;
1040 	if (bsize < count)
1041 	    return_error(gs_error_unregistered); /* Must not happen. */
1042 	memcpy(buf, (const byte *)pte->text.data.bytes + pte->index, count);
1043     } else if (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR)) {
1044 	/* Check that all chars fit in a single byte. */
1045 	const gs_char *cdata;
1046 	int i;
1047 
1048 	if (operation & TEXT_FROM_CHARS) {
1049 	    cdata = pte->text.data.chars;
1050 	    count = (pte->text.size - pte->index);
1051 	} else {
1052 	    cdata = &pte->text.data.d_char;
1053 	    count = 1;
1054 	}
1055 	if (bsize < count * sizeof(gs_char))
1056 	    return_error(gs_error_unregistered); /* Must not happen. */
1057 	for (i = 0; i < count; ++i) {
1058 	    gs_char chr = cdata[pte->index + i];
1059 
1060 	    if (chr & ~0xff)
1061 		return_error(gs_error_rangecheck);
1062 	    buf[i] = (byte)chr;
1063 	}
1064     } else if (operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH)) {
1065 	/*
1066 	 * Since PDF has no analogue of 'glyphshow',
1067 	 * we try to encode glyphs with the current
1068 	 * font's encoding. If the current font has no encoding,
1069 	 * or the encoding doesn't contain necessary glyphs,
1070 	 * the text will be represented with a Type 3 font with
1071 	 * bitmaps or outlines.
1072 	 *
1073 	 * When we fail with encoding (136-01.ps is an example),
1074 	 * we could locate a PDF font resource or create a new one
1075 	 * with same outlines and an appropriate encoding.
1076 	 * Also we could change .notdef entries in the
1077 	 * copied font (assuming that document designer didn't use
1078 	 * .notdef for a meanful printing).
1079 	 * fixme: Not implemented yet.
1080 	 */
1081 	gs_font *font = pte->current_font;
1082 	uint size;
1083 	int i;
1084 
1085 	if (operation & TEXT_FROM_GLYPHS) {
1086 	    gdata = pte->text.data.glyphs;
1087 	    size = pte->text.size - pte->index;
1088 	} else {
1089 	    gdata = &pte->text.data.d_glyph;
1090 	    size = 1;
1091 	}
1092 	if (!pdf_is_simple_font(font))
1093 	    return_error(gs_error_unregistered); /* Must not happen. */
1094 	count = 0;
1095 	for (i = 0; i < size; ++i) {
1096 	    gs_glyph glyph = gdata[pte->index + i];
1097 	    int char_code_length;
1098 
1099 	    code = pdf_encode_glyph((gs_font_base *)font, glyph,
1100 			 buf + count, size - count, &char_code_length);
1101 	    if (code < 0)
1102 		break;
1103 	    count += char_code_length;
1104 	    if (operation & TEXT_INTERVENE)
1105 		break; /* Just do one character. */
1106 	}
1107 	if (i < size) {
1108 	    pdf_font_resource_t *pdfont;
1109 
1110 	    str.data = buf;
1111 	    str.size = size;
1112 	    if (pdf_obtain_font_resource_unencoded(penum, &str, &pdfont, gdata) != 0) {
1113 		/*
1114 		 * pdf_text_process will fall back
1115 		 * to default implementation.
1116 		 */
1117 		return code;
1118 	    }
1119 	    count = size;
1120 	}
1121 	/*  So far we will use TEXT_FROM_STRING instead
1122 	    TEXT_FROM_*_GLYPH*. Since we used a single
1123 	    byte encoding, the character index appears invariant
1124 	    during this substitution.
1125 	 */
1126     } else
1127 	return_error(gs_error_rangecheck);
1128     str.data = buf;
1129     if (count > 1 && (operation & TEXT_INTERVENE)) {
1130 	/* Just do one character. */
1131 	str.size = 1;
1132 	code = pdf_encode_process_string(penum, &str, gdata, NULL, &text_state);
1133 	if (code >= 0) {
1134 	    pte->returned.current_char = buf[0];
1135 	    code = TEXT_PROCESS_INTERVENE;
1136 	}
1137     } else {
1138 	str.size = count;
1139 	code = pdf_encode_process_string(penum, &str, gdata, NULL, &text_state);
1140     }
1141     return code;
1142 }
1143