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