1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Composite and CID-based text processing for pdfwrite. */
18 #include "memory_.h"
19 #include "gx.h"
20 #include "gserrors.h"
21 #include "gxfcmap.h"
22 #include "gxfont.h"
23 #include "gxfont0.h"
24 #include "gxfont0c.h"
25 #include "gzpath.h"
26 #include "gxchar.h"
27 #include "gdevpsf.h"
28 #include "gdevpdfx.h"
29 #include "gdevpdtx.h"
30 #include "gdevpdtd.h"
31 #include "gdevpdtf.h"
32 #include "gdevpdts.h"
33 #include "gdevpdtt.h"
34 
35 /* ---------------- Non-CMap-based composite font ---------------- */
36 
37 /*
38  * Process a text string in a composite font with FMapType != 9 (CMap).
39  */
40 int
process_composite_text(gs_text_enum_t * pte,void * vbuf,uint bsize)41 process_composite_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
42 {
43     byte *const buf = vbuf;
44     pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
45     int code = 0;
46     gs_string str;
47     pdf_text_process_state_t text_state;
48     pdf_text_enum_t curr, prev, out;
49     gs_point total_width;
50     const gs_matrix *psmat = 0;
51     gs_font *prev_font = 0;
52     gs_char chr, char_code = 0x0badf00d, space_char = GS_NO_CHAR;
53     int buf_index = 0;
54     bool return_width = (penum->text.operation & TEXT_RETURN_WIDTH);
55 
56     str.data = buf;
57     if (return_width) {
58         code = gx_path_current_point(penum->path, &penum->origin);
59         if (code < 0)
60             return code;
61     }
62     if (pte->text.operation &
63         (TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
64         )
65         return_error(gs_error_rangecheck);
66     if (pte->text.operation & TEXT_INTERVENE) {
67         /* Not implemented. (PostScript doesn't even allow this case.) */
68         return_error(gs_error_rangecheck);
69     }
70     total_width.x = total_width.y = 0;
71     curr = *penum;
72     prev = curr;
73     out = curr;
74     out.current_font = 0;
75     /* Scan runs of characters in the same leaf font. */
76     for ( ; ; ) {
77         int font_code;
78         gs_font *new_font = 0;
79 
80         gs_text_enum_copy_dynamic((gs_text_enum_t *)&out,
81                                   (gs_text_enum_t *)&curr, false);
82         for (;;) {
83             gs_glyph glyph;
84 
85             gs_text_enum_copy_dynamic((gs_text_enum_t *)&prev,
86                                       (gs_text_enum_t *)&curr, false);
87             font_code = pte->orig_font->procs.next_char_glyph
88                 ((gs_text_enum_t *)&curr, &chr, &glyph);
89             /*
90              * We check for a font change by comparing the current
91              * font, rather than testing the return code, because
92              * it makes the control structure a little simpler.
93              */
94             switch (font_code) {
95             case 0:		/* no font change */
96             case 1:		/* font change */
97                 curr.returned.current_char = chr;
98                 char_code = gx_current_char((gs_text_enum_t *)&curr);
99                 new_font = curr.fstack.items[curr.fstack.depth].font;
100                 if (new_font != prev_font)
101                     break;
102                 if (chr != (byte)chr)	/* probably can't happen */
103                     return_error(gs_error_rangecheck);
104                 if (buf_index >= bsize)
105                     return_error(gs_error_unregistered); /* Must not happen. */
106                 buf[buf_index] = (byte)chr;
107                 buf_index++;
108                 prev_font = new_font;
109                 psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
110                 if ((pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) &&
111                         pte->text.space.s_char == char_code)
112                     space_char = chr;
113                 continue;
114             case 2:		/* end of string */
115                 break;
116             default:	/* error */
117                 return font_code;
118             }
119             break;
120         }
121         str.size = buf_index;
122         if (buf_index) {
123             /* buf_index == 0 is only possible the very first time. */
124             /*
125              * The FontMatrix of leaf descendant fonts is not updated
126              * by scalefont.  Compute the effective FontMatrix now.
127              */
128             gs_matrix fmat;
129 
130             /* set up the base font : */
131             out.fstack.depth = 0;
132             out.fstack.items[out.fstack.depth].font = out.current_font = prev_font;
133             pte->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             out.index = 0; /* Note : we don't reset out.xy_index here. */
140             code = pdf_process_string_aux(&out, &str, NULL, &fmat, &text_state);
141             if (code < 0)
142                 return code;
143             curr.xy_index = out.xy_index; /* pdf_encode_process_string advanced it. */
144             if (out.index < str.size) {
145                 gs_glyph glyph;
146 
147                 /* Advance *pte exactly for out.index chars,
148                    because above we stored bytes into buf. */
149                 while (out.index--)
150                     pte->orig_font->procs.next_char_glyph(pte, &chr, &glyph);
151                 font_code = 2; /* force exiting the loop */
152             } else {
153                 /* advance *pte past the current substring */
154                 gs_text_enum_copy_dynamic(pte, (gs_text_enum_t *)&prev, true);
155             }
156             pte->xy_index = out.xy_index;
157             if (return_width) {
158                 /* This is silly, but its a consequence of the way pdf_process_string
159                  * works. When we have TEXT_DO_NONE (stringwidth) we add the width of the
160                  * glyph(s) to the enumerator 'returned.total_width' so we keep track
161                  * of the total width as we go. However when we are returning the width
162                  * but its NOT for a stringwidth, we set the enumerator 'retuerned'
163                  * value to just the width of the glyph(s) processed. So when we are *not*
164                  * handling a stringwidth we need to keep track of the total width
165                  * ourselves. I'd have preferred to alter pdf_process_string, but that
166                  * is used in many other places, and those places rely on this behaviour.
167                  */
168                 if (pte->text.operation & TEXT_DO_NONE) {
169                     pte->returned.total_width.x = total_width.x = out.returned.total_width.x;
170                     pte->returned.total_width.y = total_width.y = out.returned.total_width.y;
171                 } else {
172                     pte->returned.total_width.x = total_width.x +=
173                         out.returned.total_width.x;
174                     pte->returned.total_width.y = total_width.y +=
175                         out.returned.total_width.y;
176                 }
177             }
178             pdf_text_release_cgp(penum);
179         }
180         if (font_code == 2)
181             break;
182         buf[0] = (byte)chr;
183         buf_index = 1;
184         space_char = ((pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) &&
185                       pte->text.space.s_char == char_code ? chr : ~0);
186         psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
187         prev_font = new_font;
188     }
189     if (!return_width)
190         return 0;
191     return pdf_shift_text_currentpoint(penum, &total_width);
192 }
193 
194 /* ---------------- CMap-based composite font ---------------- */
195 
196 /*
197  * Process a text string in a composite font with FMapType == 9 (CMap).
198  */
199 static const char *const standard_cmap_names[] = {
200     /* The following were added in PDF 1.5. */
201 
202     "UniGB-UTF16-H", "UniGB-UTF16-V",
203 
204     "GBKp-EUC-H", "GBKp-EUC-V",
205     "HKscs-B5-H", "HKscs-B5-V",
206     "UniCNS-UTF16-H", "UniCNS-UTF16-V",
207     "UniJIS-UTF16-H", "UniJIS-UTF16-V",
208     "UniKS-UTF16-H", "UniKS-UTF16-V",
209 #define END_PDF15_CMAP_NAMES_INDEX 12
210     /* The following were added in PDF 1.4. */
211     "GBKp-EUC-H", "GBKp-EUC-V",
212     "GBK2K-H", "GBK2K-V",
213     "HKscs-B5-H", "HKscs-B5-V",
214 #define END_PDF14_CMAP_NAMES_INDEX 18
215     /* The following were added in PDF 1.3. */
216 
217     "GBpc-EUC-V",
218     "GBK-EUC-H", "GBK-EUC-V",
219     "UniGB-UCS2-H", "UniGB-UCS2-V",
220 
221     "ETenms-B5-H", "ETenms-B5-V",
222 
223     "UniCNS-UCS2-H", "UniCNS-UCS2-V",
224 
225     "90msp-RKSJ-H", "90msp-RKSJ-V",
226     "EUC-H", "EUC-V",
227     "UniJIS-UCS2-H", "UniJIS-UCS2-V",
228     "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V",
229 
230     "KSCms-UHC-HW-H", "KSCms-UHC-HW-V",
231     "UniKS-UCS2-H", "UniKS-UCS2-V",
232 
233 #define END_PDF13_CMAP_NAMES_INDEX 39
234     /* The following were added in PDF 1.2. */
235 
236     "GB-EUC-H", "GB-EUC-V",
237     "GBpc-EUC-H"
238 
239     "B5pc-H", "B5pc-V",
240     "ETen-B5-H", "ETen-B5-V",
241     "CNS-EUC-H", "CNS-EUC-V",
242 
243     "83pv-RKSJ-H",
244     "90ms-RKSJ-H", "90ms-RKSJ-V",
245     "90pv-RKSJ-H",
246     "Add-RKSJ-H", "Add-RKSJ-V",
247     "Ext-RKSJ-H", "Ext-RKSJ-V",
248     "H", "V",
249 
250     "KSC-EUC-H", "KSC-EUC-V",
251     "KSCms-UHC-H", "KSCms-UHC-V",
252     "KSCpc-EUC-H",
253 
254     "Identity-H", "Identity-V",
255 
256     0
257 };
258 
259 static int
attach_cmap_resource(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,const gs_cmap_t * pcmap,int font_index_only)260 attach_cmap_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
261                 const gs_cmap_t *pcmap, int font_index_only)
262 {
263     const char *const *pcmn =
264         standard_cmap_names +
265         (pdev->CompatibilityLevel < 1.3 ? END_PDF13_CMAP_NAMES_INDEX :
266          pdev->CompatibilityLevel < 1.4 ? END_PDF14_CMAP_NAMES_INDEX :
267          pdev->CompatibilityLevel < 1.5 ? END_PDF15_CMAP_NAMES_INDEX : 0);
268     bool is_identity = false;
269     pdf_resource_t *pcmres = 0;	/* CMap */
270     int code;
271 
272     /* Make sure cmap names is properly initialised. Silences Coverity warning */
273     if (!pcmn)
274         return_error(gs_error_unknownerror);
275 
276     /*
277      * If the CMap isn't standard, write it out if necessary.
278      */
279     for (; *pcmn != 0; ++pcmn)
280         if (pcmap->CMapName.size == strlen(*pcmn) &&
281             !memcmp(*pcmn, pcmap->CMapName.data, pcmap->CMapName.size))
282             break;
283     if (*pcmn == 0) {
284         /*
285          * PScript5.dll Version 5.2 creates identity CMaps with
286          * instandard name. Check this specially here
287          * and later replace with a standard name.
288          * This is a temporary fix for SF bug #615994 "CMAP is corrupt".
289          */
290         is_identity = gs_cmap_is_identity(pcmap, font_index_only);
291     }
292     if (*pcmn == 0 && !is_identity) {		/* not standard */
293         pcmres = pdf_find_resource_by_gs_id(pdev, resourceCMap, pcmap->id + font_index_only);
294         if (pcmres == 0) {
295             /* Create and write the CMap object. */
296             code = pdf_cmap_alloc(pdev, pcmap, &pcmres, font_index_only);
297             if (code < 0)
298                 return code;
299         }
300     }
301     if (pcmap->from_Unicode) {
302         gs_cmap_ranges_enum_t renum;
303 
304         gs_cmap_ranges_enum_init(pcmap, &renum);
305         if (gs_cmap_enum_next_range(&renum) == 0 && renum.range.size == 2 &&
306             gs_cmap_enum_next_range(&renum) == 1) {
307             /*
308              * Exactly one code space range, of size 2.  Add an identity
309              * ToUnicode CMap.
310              */
311             if (!pdev->Identity_ToUnicode_CMaps[pcmap->WMode]) {
312                 /* Create and write an identity ToUnicode CMap now. */
313                 gs_cmap_t *pidcmap;
314 
315                 code = gs_cmap_create_char_identity(&pidcmap, 2, pcmap->WMode,
316                                                     pdev->memory);
317                 if (code < 0)
318                     return code;
319                 pidcmap->CMapType = 2;	/* per PDF Reference */
320                 pidcmap->ToUnicode = true;
321                 code = pdf_cmap_alloc(pdev, pidcmap,
322                                 &pdev->Identity_ToUnicode_CMaps[pcmap->WMode], -1);
323                 if (code < 0)
324                     return code;
325             }
326             pdfont->res_ToUnicode = pdev->Identity_ToUnicode_CMaps[pcmap->WMode];
327         }
328     }
329     if (pcmres || is_identity) {
330         uint size = pcmap->CMapName.size;
331         byte *chars = gs_alloc_string(pdev->pdf_memory, size,
332                                       "pdf_font_resource_t(CMapName)");
333 
334         if (chars == 0)
335             return_error(gs_error_VMerror);
336         memcpy(chars, pcmap->CMapName.data, size);
337         if (is_identity)
338             strcpy(pdfont->u.type0.Encoding_name,
339                     (pcmap->WMode ? "/Identity-V" : "/Identity-H"));
340         else
341             sprintf(pdfont->u.type0.Encoding_name, "%ld 0 R",
342                     pdf_resource_id(pcmres));
343         pdfont->u.type0.CMapName.data = chars;
344         pdfont->u.type0.CMapName.size = size;
345     } else {
346         if (!*pcmn)
347             /* Should not be possible, if *pcmn is NULL then either
348              * is_identity is true or we create pcmres.
349              */
350             return_error(gs_error_invalidfont);
351 
352         sprintf(pdfont->u.type0.Encoding_name, "/%s", *pcmn);
353         pdfont->u.type0.CMapName.data = (const byte *)*pcmn;
354         pdfont->u.type0.CMapName.size = strlen(*pcmn);
355         pdfont->u.type0.cmap_is_standard = true;
356     }
357     pdfont->u.type0.WMode = pcmap->WMode;
358     return 0;
359 }
360 
361 /* Record widths and CID => GID mappings. */
362 static int
scan_cmap_text(pdf_text_enum_t * pte,void * vbuf)363 scan_cmap_text(pdf_text_enum_t *pte, void *vbuf)
364 {
365     gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
366     /* gs_font_type0 *const font = (gs_font_type0 *)pte->current_font;*/ /* Type 0, fmap_CMap */
367     gs_font_type0 *const font = (gs_font_type0 *)pte->orig_font; /* Type 0, fmap_CMap */
368     /* Not sure. Changed for CDevProc callout. Was pte->current_font */
369     gs_text_enum_t scan = *(gs_text_enum_t *)pte;
370     int wmode = font->WMode, code, rcode = 0;
371     pdf_font_resource_t *pdsubf0 = NULL;
372     gs_font *subfont0 = NULL, *saved_subfont = NULL;
373     uint index = scan.index, xy_index = scan.xy_index, start_index = index;
374     uint font_index0 = 0x7badf00d;
375     bool done = false;
376     pdf_char_glyph_pairs_t p;
377     gs_glyph *type1_glyphs = (gs_glyph *)vbuf;
378     int num_type1_glyphs = 0;
379 
380     p.num_all_chars = 1;
381     p.num_unused_chars = 1;
382     p.unused_offset = 0;
383     pte->returned.total_width.x = pte->returned.total_width.y = 0;;
384     for (;;) {
385         uint break_index, break_xy_index;
386         uint font_index = 0x7badf00d;
387         gs_const_string str;
388         pdf_text_process_state_t text_state;
389         pdf_font_resource_t *pdsubf;
390         gs_font *subfont = NULL;
391         gs_point wxy;
392         bool font_change = 0;
393 
394         code = gx_path_current_point(pte->path, &pte->origin);
395         if (code < 0)
396             return code;
397         do {
398             gs_char chr;
399             gs_glyph glyph;
400             pdf_font_descriptor_t *pfd;
401             byte *glyph_usage;
402             double *real_widths, *w, *v, *w0;
403             int char_cache_size, width_cache_size;
404             gs_char cid;
405 
406             break_index = scan.index;
407             break_xy_index = scan.xy_index;
408             code = font->procs.next_char_glyph(&scan, &chr, &glyph);
409             if (code == 2) {		/* end of string */
410                 done = true;
411                 break;
412             }
413             if (code < 0)
414                 return code;
415             subfont = scan.fstack.items[scan.fstack.depth].font;
416             font_index = scan.fstack.items[scan.fstack.depth - 1].index;
417             scan.xy_index++;
418             if (glyph == GS_NO_GLYPH)
419                 glyph = GS_MIN_CID_GLYPH;
420             cid = glyph - GS_MIN_CID_GLYPH;
421             switch (subfont->FontType) {
422                 case ft_encrypted:
423                 case ft_encrypted2:{
424                     if (glyph == GS_MIN_CID_GLYPH) {
425                         glyph = subfont->procs.encode_char(subfont, chr, GLYPH_SPACE_NAME);
426                     }
427                     type1_glyphs[num_type1_glyphs] = glyph;
428                     num_type1_glyphs++;
429                     break;
430                 }
431                 case ft_CID_encrypted:
432                 case ft_CID_TrueType: {
433                     p.s[0].glyph = glyph;
434                     p.s[0].chr = cid;
435                     code = pdf_obtain_cidfont_resource(pdev, subfont, &pdsubf, &p);
436                     if (code < 0)
437                         return code;
438                     break;
439                 }
440                 case ft_user_defined: {
441                     gs_string str1;
442 
443                     str1.data = NULL;
444                     str1.size = 0;
445                     pte->current_font = subfont;
446                     code = pdf_obtain_font_resource(pte, &str1, &pdsubf);
447                     if (code < 0)
448                         return code;
449                     cid = pdf_find_glyph(pdsubf, glyph);
450                     if (cid == GS_NO_CHAR) {
451                         code = pdf_make_font3_resource(pdev, subfont, &pdsubf);
452                         if (code < 0)
453                             return code;
454                         code = pdf_attach_font_resource(pdev, subfont, pdsubf);
455                         if (code < 0)
456                             return code;
457                         cid = 0;
458                     }
459                     break;
460                 }
461                 default:
462                     /* An unsupported case, fall back to default implementation. */
463                     return_error(gs_error_rangecheck);
464             }
465             code = pdf_attached_font_resource(pdev, (gs_font *)subfont, &pdsubf,
466                                        &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
467             if (code < 0)
468                 return code;
469             if (break_index > start_index && pdev->charproc_just_accumulated)
470                 break;
471             if (subfont->FontType == ft_user_defined &&
472                 (break_index > start_index || !pdev->charproc_just_accumulated) &&
473                 !(pdsubf->u.simple.s.type3.cached[cid >> 3] & (0x80 >> (cid & 7)))) {
474                 pte->current_font = subfont;
475                 return gs_error_undefined;
476             }
477             if (subfont->FontType == ft_encrypted || subfont->FontType == ft_encrypted2) {
478                 font_change = (subfont != subfont0 && subfont0 != NULL);
479                 if (font_change) {
480                     saved_subfont = subfont;
481                     subfont = subfont0;
482                     num_type1_glyphs--;
483                 }
484             } else
485                 font_change = (pdsubf != pdsubf0 && pdsubf0 != NULL);
486             if (!font_change) {
487                 pdsubf0 = pdsubf;
488                 font_index0 = font_index;
489                 subfont0 = subfont;
490             }
491             if (subfont->FontType != ft_encrypted && subfont->FontType != ft_encrypted2) {
492                 pfd = pdsubf->FontDescriptor;
493                 code = pdf_resize_resource_arrays(pdev, pdsubf, cid + 1);
494                 if (code < 0)
495                     return code;
496                 if (subfont->FontType == ft_CID_encrypted || subfont->FontType == ft_CID_TrueType) {
497                     if (cid >=width_cache_size) {
498                         /* fixme: we add the CID=0 glyph as CID=cid glyph to the output font.
499                            Really it must not add and leave the CID undefined. */
500                         cid = 0; /* notdef. */
501                     }
502                 }
503                 if (cid >= char_cache_size || cid >= width_cache_size)
504                     return_error(gs_error_unregistered); /* Must not happen */
505                 if (pdsubf->FontType == ft_user_defined  || pdsubf->FontType == ft_encrypted ||
506                                 pdsubf->FontType == ft_encrypted2) {
507                 } else {
508                     pdf_font_resource_t *pdfont;
509                     bool notdef_subst = false;
510 
511                     code = pdf_obtain_cidfont_widths_arrays(pdev, pdsubf, wmode, &w, &w0, &v);
512                     if (code < 0)
513                         return code;
514                     code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf, font_index,
515                         &font->data.CMap->CMapName, &pdfont);
516                     if (code < 0)
517                         return code;
518                     if (pdf_is_CID_font(subfont)) {
519                         if (subfont->procs.decode_glyph((gs_font *)subfont, glyph, -1) != GS_NO_CHAR) {
520                             /* Since PScript5.dll creates GlyphNames2Unicode with character codes
521                                instead CIDs, and with the WinCharSetFFFF-H2 CMap
522                                character codes appears different than CIDs (Bug 687954),
523                                pass the character code intead the CID. */
524                             code = pdf_add_ToUnicode(pdev, subfont, pdfont,
525                                 chr + GS_MIN_CID_GLYPH, chr, NULL);
526                         } else {
527                             /* If we interpret a PDF document, ToUnicode
528                                CMap may be attached to the Type 0 font. */
529                             code = pdf_add_ToUnicode(pdev, pte->orig_font, pdfont,
530                                 chr + GS_MIN_CID_GLYPH, chr, NULL);
531                         }
532                     } else
533                         code = pdf_add_ToUnicode(pdev, subfont, pdfont, glyph, cid, NULL);
534                     if (code < 0)
535                         return code;
536                     /*  We can't check pdsubf->used[cid >> 3] here,
537                         because it mixed data for different values of WMode.
538                         Perhaps pdf_font_used_glyph returns fast with reused glyphs.
539                      */
540                     code = pdf_font_used_glyph(pfd, glyph, (gs_font_base *)subfont);
541                     if (code == gs_error_rangecheck) {
542                         if (!(pdsubf->used[cid >> 3] & (0x80 >> (cid & 7)))) {
543                             char buf[gs_font_name_max + 1];
544                             int l = min(sizeof(buf) - 1, subfont->font_name.size);
545 
546                             memcpy(buf, subfont->font_name.chars, l);
547                             buf[l] = 0;
548                             emprintf3(pdev->memory,
549                                       "Missing glyph CID=%d, glyph=%04x in the font %s . The output PDF may fail with some viewers.\n",
550                                       (int)cid,
551                                       (unsigned int)(glyph - GS_MIN_CID_GLYPH),
552                                       buf);
553                             pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
554                         }
555                         cid = 0, code = 1;  /* undefined glyph. */
556                         notdef_subst = true;
557                         /* If this is the first use of CID=0, get its width */
558                         if (pdsubf->Widths[cid] == 0) {
559                             pdf_glyph_widths_t widths;
560 
561                             code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths,
562                                 pte->cdevproc_callout ? pte->cdevproc_result : NULL);
563                         }
564                     } else if (code < 0)
565                         return code;
566                     if ((code == 0 /* just copied */ || pdsubf->Widths[cid] == 0) && !notdef_subst) {
567                         pdf_glyph_widths_t widths;
568 
569                     code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths,
570                         pte->cdevproc_callout ? pte->cdevproc_result : NULL);
571                     if (code < 0)
572                         return code;
573                     if (code == TEXT_PROCESS_CDEVPROC) {
574                         pte->returned.current_glyph = glyph;
575                         pte->current_font = subfont;
576                         rcode = TEXT_PROCESS_CDEVPROC;
577                         break;
578                     }
579                     if (code >= 0) {
580                         if (cid > pdsubf->count)
581                             return_error(gs_error_unregistered); /* Must not happen. */
582                         w[cid] = widths.Width.w;
583                         if (v != NULL) {
584                             v[cid * 2 + 0] = widths.Width.v.x;
585                             v[cid * 2 + 1] = widths.Width.v.y;
586                         }
587                         real_widths[cid] = widths.real_width.w;
588                     }
589                     if (wmode) {
590                         /* Since AR5 use W or DW to compute the x-coordinate of
591                            v-vector, comupte and store the glyph width for WMode 0. */
592                         /* fixme : skip computing real_width here. */
593                         code = pdf_glyph_widths(pdsubf, 0, glyph, (gs_font *)subfont, &widths,
594                             pte->cdevproc_callout ? pte->cdevproc_result : NULL);
595                         if (code < 0)
596                             return code;
597                         w0[cid] = widths.Width.w;
598                     }
599                     if (pdsubf->u.cidfont.CIDToGIDMap != 0) {
600                         gs_font_cid2 *subfont2 = (gs_font_cid2 *)subfont;
601 
602                         pdsubf->u.cidfont.CIDToGIDMap[cid] =
603                         subfont2->cidata.CIDMap_proc(subfont2, glyph);
604                     }
605                 }
606                 if (wmode)
607                     pdsubf->u.cidfont.used2[cid >> 3] |= 0x80 >> (cid & 7);
608                 }
609                 pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
610             }
611             if (pte->cdevproc_callout) {
612                 /* Only handle a single character because its width is stored
613                   into pte->cdevproc_result, and process_text_modify_width neds it.
614                   fixme: next time take from w, v, real_widths. */
615                 break_index = scan.index;
616                 break_xy_index = scan.xy_index;
617                 break;
618             }
619         } while (!font_change);
620         if (break_index > index) {
621             pdf_font_resource_t *pdfont;
622             gs_matrix m3;
623             int xy_index_step = (!(pte->text.operation & TEXT_REPLACE_WIDTHS) ? 0 :
624                                  pte->text.x_widths == pte->text.y_widths ? 2 : 1);
625             gs_text_params_t save_text;
626 
627             if (!subfont && num_type1_glyphs != 0)
628                 subfont = subfont0;
629             if (subfont && (subfont->FontType == ft_encrypted || subfont->FontType == ft_encrypted2)) {
630                 int save_op = pte->text.operation;
631                 gs_font *save_font = pte->current_font;
632                 const gs_glyph *save_data = pte->text.data.glyphs;
633 
634                 pte->current_font = subfont;
635                 pte->text.operation |= TEXT_FROM_GLYPHS;
636                 pte->text.data.glyphs = type1_glyphs;
637                 str.data = ((const byte *)vbuf) + ((pte->text.size - pte->index) * sizeof(gs_glyph));
638                 str.size = num_type1_glyphs;
639                 code = pdf_obtain_font_resource_unencoded(pte, (const gs_string *)&str, &pdsubf0,
640                     type1_glyphs);
641                 if (code < 0) {
642                     /* Replace the modified values, fall back to default implementation
643                      * (type 3 bitmap image font)
644                      */
645                     pte->current_font = save_font;
646                     pte->text.operation |= save_op;
647                     pte->text.data.glyphs = save_data;
648                     return(code);
649                 }
650                 memcpy((void *)scan.text.data.bytes, (void *)str.data, str.size);
651                 str.data = scan.text.data.bytes;
652                 pdsubf = pdsubf0;
653                 pte->text.operation = save_op;
654             }
655             pte->current_font = subfont0;
656             if (!subfont0 || !pdsubf0)
657                 /* This should be impossible */
658                 return_error(gs_error_invalidfont);
659 
660             code = gs_matrix_multiply(&subfont0->FontMatrix, &font->FontMatrix, &m3);
661             /* We thought that it should be gs_matrix_multiply(&font->FontMatrix, &subfont0->FontMatrix, &m3); */
662             if (code < 0)
663                 return code;
664             if (pdsubf0->FontType == ft_user_defined  || pdsubf->FontType == ft_encrypted ||
665                 pdsubf->FontType == ft_encrypted2)
666                     pdfont = pdsubf0;
667             else {
668                 code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf0, font_index0,
669                             &font->data.CMap->CMapName, &pdfont);
670                 if (code < 0)
671                     return code;
672                 if (!pdfont->u.type0.Encoding_name[0]) {
673                     /*
674                     * If pdfont->u.type0.Encoding_name is set,
675                     * a CMap resource is already attached.
676                     * See attach_cmap_resource.
677                     */
678                     code = attach_cmap_resource(pdev, pdfont, font->data.CMap, font_index0);
679                     if (code < 0)
680                         return code;
681                 }
682             }
683             pdf_set_text_wmode(pdev, font->WMode);
684             code = pdf_update_text_state(&text_state, (pdf_text_enum_t *)pte, pdfont, &m3);
685             if (code < 0)
686                 return code;
687             /* process_text_modify_width breaks text parameters.
688                We would like to improve it someday.
689                Now save them locally and restore after the call. */
690             save_text = pte->text;
691             if (subfont && (subfont->FontType != ft_encrypted &&
692                 subfont->FontType != ft_encrypted2)) {
693                 /* If we are a type 1 descendant, we already sorted this out above */
694                 str.data = scan.text.data.bytes + index;
695                 str.size = break_index - index;
696             }
697             if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
698                 if (pte->text.x_widths != NULL)
699                     pte->text.x_widths += xy_index * xy_index_step;
700                 if (pte->text.y_widths != NULL)
701                     pte->text.y_widths += xy_index * xy_index_step;
702             }
703             pte->xy_index = 0;
704             if (subfont && (subfont->FontType == ft_encrypted ||
705                 subfont->FontType == ft_encrypted2)) {
706                 gs_font *f = pte->orig_font;
707 
708                 adjust_first_last_char(pdfont, (byte *)str.data, str.size);
709 
710                 /* Make sure we use the descendant font, not the original type 0 ! */
711                 pte->orig_font = subfont;
712                 code = process_text_modify_width((pdf_text_enum_t *)pte,
713                     (gs_font *)subfont, &text_state, &str, &wxy, type1_glyphs, false);
714                 if (code < 0)
715                     return(code);
716                 if(font_change) {
717                     type1_glyphs[0] = type1_glyphs[num_type1_glyphs];
718                     num_type1_glyphs = 1;
719                     subfont = saved_subfont;
720                 } else {
721                     num_type1_glyphs = 0;
722                 }
723                 pte->orig_font = f;
724             } else {
725                 code = process_text_modify_width((pdf_text_enum_t *)pte, (gs_font *)font,
726                     &text_state, &str, &wxy, NULL, true);
727             }
728             if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
729                 if (pte->text.x_widths != NULL)
730                     pte->text.x_widths -= xy_index * xy_index_step;
731                 if (pte->text.y_widths != NULL)
732                     pte->text.y_widths -= xy_index * xy_index_step;
733             }
734             pte->text = save_text;
735             pte->cdevproc_callout = false;
736             if (code < 0) {
737                 pte->index = index;
738                 pte->xy_index = xy_index;
739                 return code;
740             }
741             pte->index = break_index;
742             pte->xy_index = break_xy_index;
743             code = pdf_shift_text_currentpoint(pte, &wxy);
744             if (code < 0)
745                 return code;
746         }
747         pdf_text_release_cgp(pte);
748         index = break_index;
749         xy_index = break_xy_index;
750         if (done || rcode != 0)
751             break;
752         pdsubf0 = pdsubf;
753         font_index0 = font_index;
754         subfont0 = subfont;
755     }
756     pte->index = index;
757     pte->xy_index = xy_index;
758     return rcode;
759 }
760 
761 int
process_cmap_text(gs_text_enum_t * penum,void * vbuf,uint bsize)762 process_cmap_text(gs_text_enum_t *penum, void *vbuf, uint bsize)
763 {
764     int code;
765     pdf_text_enum_t *pte = (pdf_text_enum_t *)penum;
766 
767     if (pte->text.operation &
768         (TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
769         )
770         return_error(gs_error_rangecheck);
771     if (pte->text.operation & TEXT_INTERVENE) {
772         /* Not implemented.  (PostScript doesn't allow TEXT_INTERVENE.) */
773         return_error(gs_error_rangecheck);
774     }
775     code = scan_cmap_text(pte, vbuf);
776     if (code == TEXT_PROCESS_CDEVPROC)
777         pte->cdevproc_callout = true;
778     else
779         pte->cdevproc_callout = false;
780     return code;
781 }
782 
783 /* ---------------- CIDFont ---------------- */
784 
785 /*
786  * Process a text string in a CIDFont.  (Only glyphshow is supported.)
787  */
788 int
process_cid_text(gs_text_enum_t * pte,void * vbuf,uint bsize)789 process_cid_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
790 {
791     pdf_text_enum_t *penum = (pdf_text_enum_t *)pte;
792     uint operation = pte->text.operation;
793     gs_text_enum_t save;
794     gs_font *scaled_font = pte->current_font; /* CIDFont */
795     gs_font *font;		/* unscaled font (CIDFont) */
796     const gs_glyph *glyphs;
797     gs_matrix scale_matrix;
798     pdf_font_resource_t *pdsubf; /* CIDFont */
799     gs_font_type0 *font0 = NULL;
800     uint size;
801     int code;
802 
803     if (operation & TEXT_FROM_GLYPHS) {
804         glyphs = pte->text.data.glyphs;
805         size = pte->text.size - pte->index;
806     } else if (operation & TEXT_FROM_SINGLE_GLYPH) {
807         glyphs = &pte->text.data.d_glyph;
808         size = 1;
809     } else if (operation & TEXT_FROM_STRING) {
810         glyphs = &pte->outer_CID;
811         size = 1;
812     } else
813         return_error(gs_error_rangecheck);
814 
815     /*
816      * PDF doesn't support glyphshow directly: we need to create a Type 0
817      * font with an Identity CMap.  Make sure all the glyph numbers fit
818      * into 16 bits.  (Eventually we should support wider glyphs too,
819      * but this would require a different CMap.)
820      */
821     if (bsize < size * 2)
822         return_error(gs_error_unregistered); /* Must not happen. */
823     {
824         int i;
825         byte *pchars = vbuf;
826 
827         for (i = 0; i < size; ++i) {
828             ulong gnum = glyphs[i] - GS_MIN_CID_GLYPH;
829 
830             if (gnum & ~0xffffL)
831                 return_error(gs_error_rangecheck);
832             *pchars++ = (byte)(gnum >> 8);
833             *pchars++ = (byte)gnum;
834         }
835     }
836 
837     /* Find the original (unscaled) version of this font. */
838 
839     for (font = scaled_font; font->base != font; )
840         font = font->base;
841     /* Compute the scaling matrix. */
842     gs_matrix_invert(&font->FontMatrix, &scale_matrix);
843     gs_matrix_multiply(&scale_matrix, &scaled_font->FontMatrix, &scale_matrix);
844 
845     /* Find or create the CIDFont resource. */
846 
847     code = pdf_obtain_font_resource(penum, NULL, &pdsubf);
848     if (code < 0)
849         return code;
850 
851     /* Create the CMap and Type 0 font if they don't exist already. */
852 
853     if (pdsubf->u.cidfont.glyphshow_font_id != 0)
854         font0 = (gs_font_type0 *)gs_find_font_by_id(font->dir,
855                     pdsubf->u.cidfont.glyphshow_font_id, &scaled_font->FontMatrix);
856     if (font0 == NULL) {
857         code = gs_font_type0_from_cidfont(&font0, font, font->WMode,
858                                           &scale_matrix, font->memory);
859         if (code < 0)
860             return code;
861         pdsubf->u.cidfont.glyphshow_font_id = font0->id;
862     }
863 
864     /* Now handle the glyphshow as a show in the Type 0 font. */
865 
866     save = *pte;
867     pte->current_font = pte->orig_font = (gs_font *)font0;
868     /* Patch the operation temporarily for init_fstack. */
869     pte->text.operation = (operation & ~TEXT_FROM_ANY) | TEXT_FROM_BYTES;
870     /* Patch the data for process_cmap_text. */
871     pte->text.data.bytes = vbuf;
872     pte->text.size = size * 2;
873     pte->index = 0;
874     gs_type0_init_fstack(pte, pte->current_font);
875     code = process_cmap_text(pte, vbuf, bsize);
876     pte->current_font = scaled_font;
877     pte->orig_font = save.orig_font;
878     pte->text = save.text;
879     pte->index = save.index + pte->index / 2;
880     pte->fstack = save.fstack;
881     return code;
882 }
883