1 /* Copyright (C) 2002 Aladdin Enterprises. 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: gdevpdtc.c,v 1.42 2005/04/27 16:40:44 igor Exp $ */
18 /* Composite and CID-based text processing for pdfwrite. */
19 #include "memory_.h"
20 #include "string_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gxfcmap.h"
24 #include "gxfont.h"
25 #include "gxfont0.h"
26 #include "gxfont0c.h"
27 #include "gzpath.h"
28 #include "gxchar.h"
29 #include "gdevpsf.h"
30 #include "gdevpdfx.h"
31 #include "gdevpdtx.h"
32 #include "gdevpdtd.h"
33 #include "gdevpdtf.h"
34 #include "gdevpdts.h"
35 #include "gdevpdtt.h"
36
37 /* ---------------- Non-CMap-based composite font ---------------- */
38
39 /*
40 * Process a text string in a composite font with FMapType != 9 (CMap).
41 */
42 int
process_composite_text(gs_text_enum_t * pte,void * vbuf,uint bsize)43 process_composite_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
44 {
45 byte *const buf = vbuf;
46 pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
47 int code = 0;
48 gs_string str;
49 pdf_text_process_state_t text_state;
50 pdf_text_enum_t curr, prev, out;
51 gs_point total_width;
52 const gs_matrix *psmat = 0;
53 gs_font *prev_font = 0;
54 gs_char chr, char_code = 0x0badf00d, space_char = GS_NO_CHAR;
55 int buf_index = 0;
56 bool return_width = (penum->text.operation & TEXT_RETURN_WIDTH);
57
58 str.data = buf;
59 if (return_width) {
60 code = gx_path_current_point(penum->path, &penum->origin);
61 if (code < 0)
62 return code;
63 }
64 if (pte->text.operation &
65 (TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
66 )
67 return_error(gs_error_rangecheck);
68 if (pte->text.operation & TEXT_INTERVENE) {
69 /* Not implemented. (PostScript doesn't even allow this case.) */
70 return_error(gs_error_rangecheck);
71 }
72 total_width.x = total_width.y = 0;
73 curr = *penum;
74 prev = curr;
75 out = curr;
76 out.current_font = 0;
77 /* Scan runs of characters in the same leaf font. */
78 for ( ; ; ) {
79 int font_code;
80 gs_font *new_font = 0;
81
82 gs_text_enum_copy_dynamic((gs_text_enum_t *)&out,
83 (gs_text_enum_t *)&curr, false);
84 for (;;) {
85 gs_glyph glyph;
86
87 gs_text_enum_copy_dynamic((gs_text_enum_t *)&prev,
88 (gs_text_enum_t *)&curr, false);
89 font_code = pte->orig_font->procs.next_char_glyph
90 ((gs_text_enum_t *)&curr, &chr, &glyph);
91 /*
92 * We check for a font change by comparing the current
93 * font, rather than testing the return code, because
94 * it makes the control structure a little simpler.
95 */
96 switch (font_code) {
97 case 0: /* no font change */
98 case 1: /* font change */
99 curr.returned.current_char = chr;
100 char_code = gx_current_char((gs_text_enum_t *)&curr);
101 new_font = curr.fstack.items[curr.fstack.depth].font;
102 if (new_font != prev_font)
103 break;
104 if (chr != (byte)chr) /* probably can't happen */
105 return_error(gs_error_rangecheck);
106 if (buf_index >= bsize)
107 return_error(gs_error_unregistered); /* Must not happen. */
108 buf[buf_index] = (byte)chr;
109 buf_index++;
110 prev_font = new_font;
111 psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
112 if (pte->text.space.s_char == char_code)
113 space_char = chr;
114 continue;
115 case 2: /* end of string */
116 break;
117 default: /* error */
118 return font_code;
119 }
120 break;
121 }
122 str.size = buf_index;
123 if (buf_index) {
124 /* buf_index == 0 is only possible the very first time. */
125 /*
126 * The FontMatrix of leaf descendant fonts is not updated
127 * by scalefont. Compute the effective FontMatrix now.
128 */
129 gs_matrix fmat;
130
131 /* set up the base font : */
132 out.fstack.depth = 0;
133 out.fstack.items[out.fstack.depth].font = out.current_font = prev_font;
134
135 /* Provide the decoded space character : */
136 out.text.space.s_char = space_char;
137
138 gs_matrix_multiply(&prev_font->FontMatrix, psmat, &fmat);
139 code = pdf_encode_process_string(&out, &str, NULL, &fmat, &text_state);
140 if (code < 0)
141 return code;
142 curr.xy_index = out.xy_index; /* pdf_encode_process_string advanced it. */
143 gs_text_enum_copy_dynamic(pte, (gs_text_enum_t *)&prev, true);
144 if (return_width) {
145 pte->returned.total_width.x = total_width.x +=
146 out.returned.total_width.x;
147 pte->returned.total_width.y = total_width.y +=
148 out.returned.total_width.y;
149 }
150 pdf_text_release_cgp(penum);
151 }
152 if (font_code == 2)
153 break;
154 buf[0] = (byte)chr;
155 buf_index = 1;
156 space_char = (pte->text.space.s_char == char_code ? chr : ~0);
157 psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
158 prev_font = new_font;
159 }
160 if (!return_width)
161 return 0;
162 return pdf_shift_text_currentpoint(penum, &total_width);
163 }
164
165 /* ---------------- CMap-based composite font ---------------- */
166
167 /*
168 * Process a text string in a composite font with FMapType == 9 (CMap).
169 */
170 private const char *const standard_cmap_names[] = {
171 /* The following were added in PDF 1.4. */
172 "GBKp-EUC-H", "GBKp-EUC-V",
173 "GBK2K-H", "GBK2K-V",
174 "HKscs-B5-H", "HKscs-B5-V",
175 #define END_PDF14_CMAP_NAMES_INDEX 6
176
177 "Identity-H", "Identity-V",
178
179 "GB-EUC-H", "GB-EUC-V",
180 "GBpc-EUC-H", "GBpc-EUC-V",
181 "GBK-EUC-H", "GBK-EUC-V",
182 "UniGB-UCS2-H", "UniGB-UCS2-V",
183
184 "B5pc-H", "B5pc-V",
185 "ETen-B5-H", "ETen-B5-V",
186 "ETenms-B5-H", "ETenms-B5-V",
187 "CNS-EUC-H", "CNS-EUC-V",
188 "UniCNS-UCS2-H", "UniCNS-UCS2-V",
189
190 "83pv-RKSJ-H",
191 "90ms-RKSJ-H", "90ms-RKSJ-V",
192 "90msp-RKSJ-H", "90msp-RKSJ-V",
193 "90pv-RKSJ-H",
194 "Add-RKSJ-H", "Add-RKSJ-V",
195 "EUC-H", "EUC-V",
196 "Ext-RKSJ-H", "Ext-RKSJ-V",
197 "H", "V",
198 "UniJIS-UCS2-H", "UniJIS-UCS2-V",
199 "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V",
200
201 "KSC-EUC-H", "KSC-EUC-V",
202 "KSCms-UHC-H", "KSCms-UHC-V",
203 "KSCms-UHC-HW-H", "KSCms-UHC-HW-V",
204 "KSCpc-EUC-H",
205 "UniKS-UCS2-H", "UniKS-UCS2-V",
206
207 0
208 };
209
210 private int
attach_cmap_resource(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,const gs_cmap_t * pcmap,int font_index_only)211 attach_cmap_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
212 const gs_cmap_t *pcmap, int font_index_only)
213 {
214 const char *const *pcmn =
215 standard_cmap_names +
216 (pdev->CompatibilityLevel < 1.4 ? END_PDF14_CMAP_NAMES_INDEX : 0);
217 bool is_identity = false;
218 pdf_resource_t *pcmres = 0; /* CMap */
219 int code;
220
221 /*
222 * If the CMap isn't standard, write it out if necessary.
223 */
224 for (; *pcmn != 0; ++pcmn)
225 if (pcmap->CMapName.size == strlen(*pcmn) &&
226 !memcmp(*pcmn, pcmap->CMapName.data, pcmap->CMapName.size))
227 break;
228 if (*pcmn == 0) {
229 /*
230 * PScript5.dll Version 5.2 creates identity CMaps with
231 * instandard name. Check this specially here
232 * and later replace with a standard name.
233 * This is a temporary fix for SF bug #615994 "CMAP is corrupt".
234 */
235 is_identity = gs_cmap_is_identity(pcmap, font_index_only);
236 }
237 if (*pcmn == 0 && !is_identity) { /* not standard */
238 pcmres = pdf_find_resource_by_gs_id(pdev, resourceCMap, pcmap->id + font_index_only);
239 if (pcmres == 0) {
240 /* Create and write the CMap object. */
241 code = pdf_cmap_alloc(pdev, pcmap, &pcmres, font_index_only);
242 if (code < 0)
243 return code;
244 }
245 }
246 if (pcmap->from_Unicode) {
247 gs_cmap_ranges_enum_t renum;
248
249 gs_cmap_ranges_enum_init(pcmap, &renum);
250 if (gs_cmap_enum_next_range(&renum) == 0 && renum.range.size == 2 &&
251 gs_cmap_enum_next_range(&renum) == 1) {
252 /*
253 * Exactly one code space range, of size 2. Add an identity
254 * ToUnicode CMap.
255 */
256 if (!pdev->Identity_ToUnicode_CMaps[pcmap->WMode]) {
257 /* Create and write an identity ToUnicode CMap now. */
258 gs_cmap_t *pidcmap;
259
260 code = gs_cmap_create_char_identity(&pidcmap, 2, pcmap->WMode,
261 pdev->memory);
262 if (code < 0)
263 return code;
264 pidcmap->CMapType = 2; /* per PDF Reference */
265 code = pdf_cmap_alloc(pdev, pidcmap,
266 &pdev->Identity_ToUnicode_CMaps[pcmap->WMode], -1);
267 if (code < 0)
268 return code;
269 }
270 pdfont->res_ToUnicode = pdev->Identity_ToUnicode_CMaps[pcmap->WMode];
271 }
272 }
273 if (pcmres || is_identity) {
274 uint size = pcmap->CMapName.size;
275 byte *chars = gs_alloc_string(pdev->pdf_memory, size,
276 "pdf_font_resource_t(CMapName)");
277
278 if (chars == 0)
279 return_error(gs_error_VMerror);
280 memcpy(chars, pcmap->CMapName.data, size);
281 if (is_identity)
282 strcpy(pdfont->u.type0.Encoding_name,
283 (pcmap->WMode ? "/Identity-V" : "/Identity-H"));
284 else
285 sprintf(pdfont->u.type0.Encoding_name, "%ld 0 R",
286 pdf_resource_id(pcmres));
287 pdfont->u.type0.CMapName.data = chars;
288 pdfont->u.type0.CMapName.size = size;
289 } else {
290 sprintf(pdfont->u.type0.Encoding_name, "/%s", *pcmn);
291 pdfont->u.type0.CMapName.data = (const byte *)*pcmn;
292 pdfont->u.type0.CMapName.size = strlen(*pcmn);
293 pdfont->u.type0.cmap_is_standard = true;
294 }
295 pdfont->u.type0.WMode = pcmap->WMode;
296 return 0;
297 }
298
299 /* Record widths and CID => GID mappings. */
300 private int
scan_cmap_text(pdf_text_enum_t * pte)301 scan_cmap_text(pdf_text_enum_t *pte)
302 {
303 gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
304 /* gs_font_type0 *const font = (gs_font_type0 *)pte->current_font;*/ /* Type 0, fmap_CMap */
305 gs_font_type0 *const font = (gs_font_type0 *)pte->orig_font; /* Type 0, fmap_CMap */
306 /* Not sure. Changed for CDevProc callout. Was pte->current_font */
307 gs_text_enum_t scan = *(gs_text_enum_t *)pte;
308 int wmode = font->WMode, code, rcode = 0;
309 pdf_font_resource_t *pdsubf0 = NULL;
310 gs_font *subfont0 = NULL;
311 uint index = scan.index, xy_index = scan.xy_index;
312 uint font_index0 = 0x7badf00d;
313 bool done = false;
314 pdf_char_glyph_pairs_t p;
315
316 p.num_all_chars = 1;
317 p.num_unused_chars = 1;
318 p.unused_offset = 0;
319 pte->returned.total_width.x = pte->returned.total_width.y = 0;;
320 for (;;) {
321 uint break_index, break_xy_index;
322 uint font_index = 0x7badf00d;
323 gs_const_string str;
324 pdf_text_process_state_t text_state;
325 pdf_font_resource_t *pdsubf;
326 gs_font *subfont = NULL;
327 gs_point wxy;
328 bool font_change;
329
330 code = gx_path_current_point(pte->path, &pte->origin);
331 if (code < 0)
332 return code;
333 do {
334 gs_char chr;
335 gs_glyph glyph;
336 pdf_font_descriptor_t *pfd;
337 byte *glyph_usage;
338 double *real_widths, *w, *v, *w0;
339 int char_cache_size, width_cache_size;
340 uint cid;
341
342 break_index = scan.index;
343 break_xy_index = scan.xy_index;
344 code = font->procs.next_char_glyph(&scan, &chr, &glyph);
345 if (code == 2) { /* end of string */
346 done = true;
347 break;
348 }
349 if (code < 0)
350 return code;
351 subfont = scan.fstack.items[scan.fstack.depth].font;
352 font_index = scan.fstack.items[scan.fstack.depth].index;
353 scan.xy_index++;
354 switch (subfont->FontType) {
355 case ft_CID_encrypted:
356 case ft_CID_TrueType:
357 break;
358 default:
359 /* An unsupported case, fall back to default implementation. */
360 return_error(gs_error_rangecheck);
361 }
362 if (glyph == GS_NO_GLYPH)
363 glyph = GS_MIN_CID_GLYPH;
364 cid = glyph - GS_MIN_CID_GLYPH;
365 p.s[0].glyph = glyph;
366 p.s[0].chr = cid;
367 code = pdf_obtain_cidfont_resource(pdev, subfont, &pdsubf, &p);
368 if (code < 0)
369 return code;
370 font_change = (pdsubf != pdsubf0 && pdsubf0 != NULL);
371 if (!font_change) {
372 pdsubf0 = pdsubf;
373 font_index0 = font_index;
374 subfont0 = subfont;
375 }
376 code = pdf_attached_font_resource(pdev, (gs_font *)subfont, &pdsubf,
377 &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
378 if (code < 0)
379 return code;
380 pfd = pdsubf->FontDescriptor;
381 code = pdf_resize_resource_arrays(pdev, pdsubf, cid + 1);
382 if (code < 0)
383 return code;
384 code = pdf_obtain_cidfont_widths_arrays(pdev, pdsubf, wmode, &w, &w0, &v);
385 if (code < 0)
386 return code;
387 {
388 pdf_font_resource_t *pdfont;
389
390 code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf,
391 &font->data.CMap->CMapName, &pdfont);
392 if (code < 0)
393 return code;
394 if (pdf_is_CID_font(subfont)) {
395 /* Since PScript5.dll creates GlyphNames2Unicode with character codes
396 instead CIDs, and with the WinCharSetFFFF-H2 CMap
397 character codes appears different than CIDs (Bug 687954),
398 pass the character code intead the CID. */
399 code = pdf_add_ToUnicode(pdev, subfont, pdfont, chr + GS_MIN_CID_GLYPH, chr);
400 } else
401 code = pdf_add_ToUnicode(pdev, subfont, pdfont, glyph, cid);
402 if (code < 0)
403 return code;
404 }
405 /* We can't check pdsubf->used[cid >> 3] here,
406 because it mixed data for different values of WMode.
407 Perhaps pdf_font_used_glyph returns fast with reused glyphs.
408 */
409 code = pdf_font_used_glyph(pfd, glyph, (gs_font_base *)subfont);
410 if (code == gs_error_rangecheck) {
411 if (!(pdsubf->used[cid >> 3] & (0x80 >> (cid & 7)))) {
412 char buf[gs_font_name_max + 1];
413 int l = min(sizeof(buf) - 1, subfont->font_name.size);
414
415 memcpy(buf, subfont->font_name.chars, l);
416 buf[l] = 0;
417 eprintf2("Missing glyph CID=%d in the font %s . The output PDF may fail with some viewers.\n", cid, buf);
418 pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
419 }
420 cid = 0, code = 1; /* undefined glyph. */
421 } else if (code < 0)
422 return code;
423 if (cid >= char_cache_size || cid >= width_cache_size)
424 return_error(gs_error_unregistered); /* Must not happen */
425 if (code == 0 /* just copied */ || pdsubf->Widths[cid] == 0) {
426 pdf_glyph_widths_t widths;
427
428 code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths,
429 pte->cdevproc_callout ? pte->cdevproc_result : NULL);
430 if (code < 0)
431 return code;
432 if (code == TEXT_PROCESS_CDEVPROC) {
433 pte->returned.current_glyph = glyph;
434 pte->current_font = subfont;
435 rcode = TEXT_PROCESS_CDEVPROC;
436 break;
437 }
438 if (code == 0) { /* OK to cache */
439 if (cid > pdsubf->count)
440 return_error(gs_error_unregistered); /* Must not happen. */
441 w[cid] = widths.Width.w;
442 if (v != NULL) {
443 v[cid * 2 + 0] = widths.Width.v.x;
444 v[cid * 2 + 1] = widths.Width.v.y;
445 }
446 real_widths[cid] = widths.real_width.w;
447 }
448 if (wmode) {
449 /* Since AR5 use W or DW to compute the x-coordinate of
450 v-vector, comupte and store the glyph width for WMode 0. */
451 /* fixme : skip computing real_width here. */
452 code = pdf_glyph_widths(pdsubf, 0, glyph, (gs_font *)subfont, &widths,
453 pte->cdevproc_callout ? pte->cdevproc_result : NULL);
454 if (code < 0)
455 return code;
456 w0[cid] = widths.Width.w;
457 }
458 if (pdsubf->u.cidfont.CIDToGIDMap != 0) {
459 gs_font_cid2 *subfont2 = (gs_font_cid2 *)subfont;
460
461 pdsubf->u.cidfont.CIDToGIDMap[cid] =
462 subfont2->cidata.CIDMap_proc(subfont2, glyph);
463 }
464 }
465 pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
466 if (wmode)
467 pdsubf->u.cidfont.used2[cid >> 3] |= 0x80 >> (cid & 7);
468 if (pte->cdevproc_callout) {
469 /* Only handle a single character because its width is stored
470 into pte->cdevproc_result, and process_text_modify_width neds it.
471 fixme: next time take from w, v, real_widths. */
472 break_index = scan.index;
473 break_xy_index = scan.xy_index;
474 break;
475 }
476 } while (!font_change);
477 if (break_index > index) {
478 pdf_font_resource_t *pdfont;
479 gs_matrix m0, m1, m2, m3;
480 int xy_index_step = (pte->text.x_widths != NULL && /* see gs_text_replaced_width */
481 pte->text.x_widths == pte->text.y_widths ? 2 : 1);
482 gs_text_params_t save_text;
483
484 code = pdf_font_orig_matrix(subfont0, &m0);
485 if (code < 0)
486 return code;
487 code = gs_matrix_invert(&m0, &m1);
488 if (code < 0)
489 return code;
490 code = gs_matrix_multiply(&subfont0->FontMatrix, &m1, &m2);
491 if (code < 0)
492 return code;
493 code = gs_matrix_multiply(&m2, &font->FontMatrix, &m3);
494 /* We thought that it should be gs_matrix_multiply(&font->FontMatrix, &m2, &m3); */
495 if (code < 0)
496 return code;
497 code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf0,
498 &font->data.CMap->CMapName, &pdfont);
499 if (code < 0)
500 return code;
501 if (!pdfont->u.type0.Encoding_name[0]) {
502 /*
503 * If pdfont->u.type0.Encoding_name is set,
504 * a CMap resource is already attached.
505 * See attach_cmap_resource.
506 */
507 code = attach_cmap_resource(pdev, pdfont, font->data.CMap, font_index0);
508 if (code < 0)
509 return code;
510 }
511 pdf_set_text_wmode(pdev, font->WMode);
512 code = pdf_update_text_state(&text_state, (pdf_text_enum_t *)pte, pdfont, &m3);
513 if (code < 0)
514 return code;
515 /* process_text_modify_width breaks text parameters.
516 We would like to improve it someday.
517 Now save them locally and restore after the call. */
518 save_text = pte->text;
519 str.data = scan.text.data.bytes + index;
520 str.size = break_index - index;
521 if (pte->text.x_widths != NULL)
522 pte->text.x_widths += xy_index * xy_index_step;
523 if (pte->text.y_widths != NULL)
524 pte->text.y_widths += xy_index * xy_index_step;
525 pte->xy_index = 0;
526 code = process_text_modify_width((pdf_text_enum_t *)pte, (gs_font *)font,
527 &text_state, &str, &wxy);
528 if (pte->text.x_widths != NULL)
529 pte->text.x_widths -= xy_index * xy_index_step;
530 if (pte->text.y_widths != NULL)
531 pte->text.y_widths -= xy_index * xy_index_step;
532 pte->text = save_text;
533 pte->cdevproc_callout = false;
534 if (code < 0) {
535 pte->index = index;
536 pte->xy_index = xy_index;
537 return code;
538 }
539 pte->index = break_index;
540 pte->xy_index = break_xy_index;
541 code = pdf_shift_text_currentpoint(pte, &wxy);
542 if (code < 0)
543 return code;
544 }
545 pdf_text_release_cgp(pte);
546 index = break_index;
547 xy_index = break_xy_index;
548 if (done || rcode != 0)
549 break;
550 pdsubf0 = pdsubf;
551 font_index0 = font_index;
552 subfont0 = subfont;
553 }
554 pte->index = index;
555 pte->xy_index = xy_index;
556 return rcode;
557 }
558
559 int
process_cmap_text(gs_text_enum_t * penum,void * vbuf,uint bsize)560 process_cmap_text(gs_text_enum_t *penum, void *vbuf, uint bsize)
561 {
562 int code;
563 pdf_text_enum_t *pte = (pdf_text_enum_t *)penum;
564
565 if (pte->text.operation &
566 (TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
567 )
568 return_error(gs_error_rangecheck);
569 if (pte->text.operation & TEXT_INTERVENE) {
570 /* Not implemented. (PostScript doesn't allow TEXT_INTERVENE.) */
571 return_error(gs_error_rangecheck);
572 }
573 code = scan_cmap_text((pdf_text_enum_t *)pte);
574 if (code == TEXT_PROCESS_CDEVPROC)
575 pte->cdevproc_callout = true;
576 else
577 pte->cdevproc_callout = false;
578 return code;
579 }
580
581 /* ---------------- CIDFont ---------------- */
582
583 /*
584 * Process a text string in a CIDFont. (Only glyphshow is supported.)
585 */
586 int
process_cid_text(gs_text_enum_t * pte,void * vbuf,uint bsize)587 process_cid_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
588 {
589 pdf_text_enum_t *penum = (pdf_text_enum_t *)pte;
590 uint operation = pte->text.operation;
591 gs_text_enum_t save;
592 gs_font *scaled_font = pte->current_font; /* CIDFont */
593 gs_font *font; /* unscaled font (CIDFont) */
594 const gs_glyph *glyphs;
595 gs_matrix scale_matrix;
596 pdf_font_resource_t *pdsubf; /* CIDFont */
597 gs_font_type0 *font0 = NULL;
598 uint size;
599 int code;
600
601 if (operation & TEXT_FROM_GLYPHS) {
602 glyphs = pte->text.data.glyphs;
603 size = pte->text.size - pte->index;
604 } else if (operation & TEXT_FROM_SINGLE_GLYPH) {
605 glyphs = &pte->text.data.d_glyph;
606 size = 1;
607 } else
608 return_error(gs_error_rangecheck);
609
610 /*
611 * PDF doesn't support glyphshow directly: we need to create a Type 0
612 * font with an Identity CMap. Make sure all the glyph numbers fit
613 * into 16 bits. (Eventually we should support wider glyphs too,
614 * but this would require a different CMap.)
615 */
616 if (bsize < size * 2)
617 return_error(gs_error_unregistered); /* Must not happen. */
618 {
619 int i;
620 byte *pchars = vbuf;
621
622 for (i = 0; i < size; ++i) {
623 ulong gnum = glyphs[i] - GS_MIN_CID_GLYPH;
624
625 if (gnum & ~0xffffL)
626 return_error(gs_error_rangecheck);
627 *pchars++ = (byte)(gnum >> 8);
628 *pchars++ = (byte)gnum;
629 }
630 }
631
632 /* Find the original (unscaled) version of this font. */
633
634 for (font = scaled_font; font->base != font; )
635 font = font->base;
636 /* Compute the scaling matrix. */
637 gs_matrix_invert(&font->FontMatrix, &scale_matrix);
638 gs_matrix_multiply(&scale_matrix, &scaled_font->FontMatrix, &scale_matrix);
639
640 /* Find or create the CIDFont resource. */
641
642 code = pdf_obtain_font_resource(penum, NULL, &pdsubf);
643 if (code < 0)
644 return code;
645
646 /* Create the CMap and Type 0 font if they don't exist already. */
647
648 if (pdsubf->u.cidfont.glyphshow_font_id != 0)
649 font0 = (gs_font_type0 *)gs_find_font_by_id(font->dir,
650 pdsubf->u.cidfont.glyphshow_font_id, &scaled_font->FontMatrix);
651 if (font0 == NULL) {
652 code = gs_font_type0_from_cidfont(&font0, font, font->WMode,
653 &scale_matrix, font->memory);
654 if (code < 0)
655 return code;
656 pdsubf->u.cidfont.glyphshow_font_id = font0->id;
657 }
658
659 /* Now handle the glyphshow as a show in the Type 0 font. */
660
661 save = *pte;
662 pte->current_font = pte->orig_font = (gs_font *)font0;
663 /* Patch the operation temporarily for init_fstack. */
664 pte->text.operation = (operation & ~TEXT_FROM_ANY) | TEXT_FROM_BYTES;
665 /* Patch the data for process_cmap_text. */
666 pte->text.data.bytes = vbuf;
667 pte->text.size = size * 2;
668 pte->index = 0;
669 gs_type0_init_fstack(pte, pte->current_font);
670 code = process_cmap_text(pte, vbuf, bsize);
671 pte->current_font = scaled_font;
672 pte->orig_font = save.orig_font;
673 pte->text = save.text;
674 pte->index = save.index + pte->index / 2;
675 pte->fstack = save.fstack;
676 return code;
677 }
678