/src/ghostpdl/devices/vector/gdevpdtc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 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., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, 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 | | #include "gximage.h" |
36 | | #include "gxcpath.h" |
37 | | /* ---------------- Non-CMap-based composite font ---------------- */ |
38 | | |
39 | | /* |
40 | | * Process a text string in a composite font with FMapType != 9 (CMap). |
41 | | */ |
42 | | int |
43 | | process_composite_text(gs_text_enum_t *pte, void *vbuf, uint bsize) |
44 | 0 | { |
45 | 0 | byte *const buf = vbuf; |
46 | 0 | pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte; |
47 | 0 | int code = 0; |
48 | 0 | gs_string str; |
49 | 0 | pdf_text_process_state_t text_state; |
50 | 0 | pdf_text_enum_t curr, prev, out; |
51 | 0 | gs_point total_width; |
52 | 0 | const gs_matrix *psmat = 0; |
53 | 0 | gs_font *prev_font = 0; |
54 | 0 | gs_char chr, char_code = 0x0badf00d, space_char = GS_NO_CHAR; |
55 | 0 | int buf_index = 0; |
56 | 0 | bool return_width = (penum->text.operation & TEXT_RETURN_WIDTH); |
57 | 0 | gx_path *path = gs_text_enum_path(penum); |
58 | |
|
59 | 0 | str.data = buf; |
60 | 0 | if (return_width) { |
61 | 0 | code = gx_path_current_point(path, &penum->origin); |
62 | 0 | if (code < 0) |
63 | 0 | return code; |
64 | 0 | } |
65 | 0 | if (pte->text.operation & |
66 | 0 | (TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES)) |
67 | 0 | ) |
68 | 0 | return_error(gs_error_rangecheck); |
69 | 0 | if (pte->text.operation & TEXT_INTERVENE) { |
70 | | /* Not implemented. (PostScript doesn't even allow this case.) */ |
71 | 0 | return_error(gs_error_rangecheck); |
72 | 0 | } |
73 | 0 | total_width.x = total_width.y = 0; |
74 | 0 | curr = *penum; |
75 | 0 | prev = curr; |
76 | 0 | out = curr; |
77 | 0 | out.current_font = 0; |
78 | | /* Scan runs of characters in the same leaf font. */ |
79 | 0 | for ( ; ; ) { |
80 | 0 | int font_code; |
81 | 0 | gs_font *new_font = 0; |
82 | |
|
83 | 0 | gs_text_enum_copy_dynamic((gs_text_enum_t *)&out, |
84 | 0 | (gs_text_enum_t *)&curr, false); |
85 | 0 | for (;;) { |
86 | 0 | gs_glyph glyph; |
87 | |
|
88 | 0 | gs_text_enum_copy_dynamic((gs_text_enum_t *)&prev, |
89 | 0 | (gs_text_enum_t *)&curr, false); |
90 | 0 | font_code = pte->orig_font->procs.next_char_glyph |
91 | 0 | ((gs_text_enum_t *)&curr, &chr, &glyph); |
92 | | /* |
93 | | * We check for a font change by comparing the current |
94 | | * font, rather than testing the return code, because |
95 | | * it makes the control structure a little simpler. |
96 | | */ |
97 | 0 | switch (font_code) { |
98 | 0 | case 0: /* no font change */ |
99 | 0 | case 1: /* font change */ |
100 | 0 | curr.returned.current_char = chr; |
101 | 0 | char_code = gx_current_char((gs_text_enum_t *)&curr); |
102 | 0 | new_font = curr.fstack.items[curr.fstack.depth].font; |
103 | 0 | if (new_font != prev_font) |
104 | 0 | break; |
105 | 0 | if (chr != (byte)chr) /* probably can't happen */ |
106 | 0 | return_error(gs_error_rangecheck); |
107 | 0 | if (buf_index >= bsize) |
108 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
109 | 0 | buf[buf_index] = (byte)chr; |
110 | 0 | buf_index++; |
111 | 0 | prev_font = new_font; |
112 | 0 | psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix; |
113 | 0 | if ((pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) && |
114 | 0 | pte->text.space.s_char == char_code) |
115 | 0 | space_char = chr; |
116 | 0 | continue; |
117 | 0 | case 2: /* end of string */ |
118 | 0 | break; |
119 | 0 | default: /* error */ |
120 | 0 | return font_code; |
121 | 0 | } |
122 | 0 | break; |
123 | 0 | } |
124 | 0 | str.size = buf_index; |
125 | 0 | if (buf_index) { |
126 | | /* buf_index == 0 is only possible the very first time. */ |
127 | | /* |
128 | | * The FontMatrix of leaf descendant fonts is not updated |
129 | | * by scalefont. Compute the effective FontMatrix now. |
130 | | */ |
131 | 0 | gs_matrix fmat; |
132 | | |
133 | | /* set up the base font : */ |
134 | 0 | out.fstack.depth = 0; |
135 | 0 | out.fstack.items[out.fstack.depth].font = out.current_font = prev_font; |
136 | 0 | pte->current_font = prev_font; |
137 | | |
138 | | /* Provide the decoded space character : */ |
139 | 0 | out.text.space.s_char = space_char; |
140 | |
|
141 | 0 | gs_matrix_multiply(&prev_font->FontMatrix, psmat, &fmat); |
142 | 0 | out.index = 0; /* Note : we don't reset out.xy_index here. */ |
143 | 0 | code = pdf_process_string_aux(&out, &str, NULL, &fmat, &text_state); |
144 | 0 | if (code < 0) { |
145 | 0 | if (code == gs_error_undefined && new_font && new_font->FontType == ft_encrypted2) |
146 | | /* Caused by trying to make a CFF font resource for ps2write, which doesn't support CFF, abort now! */ |
147 | 0 | return_error(gs_error_invalidfont); |
148 | 0 | return code; |
149 | 0 | } |
150 | 0 | curr.xy_index = out.xy_index; /* pdf_encode_process_string advanced it. */ |
151 | 0 | if (out.index < str.size) { |
152 | 0 | gs_glyph glyph; |
153 | | |
154 | | /* Advance *pte exactly for out.index chars, |
155 | | because above we stored bytes into buf. */ |
156 | 0 | while (out.index--) |
157 | 0 | pte->orig_font->procs.next_char_glyph(pte, &chr, &glyph); |
158 | 0 | font_code = 2; /* force exiting the loop */ |
159 | 0 | } else { |
160 | | /* advance *pte past the current substring */ |
161 | 0 | gs_text_enum_copy_dynamic(pte, (gs_text_enum_t *)&prev, true); |
162 | 0 | } |
163 | 0 | pte->xy_index = out.xy_index; |
164 | 0 | if (return_width) { |
165 | | /* This is silly, but its a consequence of the way pdf_process_string |
166 | | * works. When we have TEXT_DO_NONE (stringwidth) we add the width of the |
167 | | * glyph(s) to the enumerator 'returned.total_width' so we keep track |
168 | | * of the total width as we go. However when we are returning the width |
169 | | * but its NOT for a stringwidth, we set the enumerator 'retuerned' |
170 | | * value to just the width of the glyph(s) processed. So when we are *not* |
171 | | * handling a stringwidth we need to keep track of the total width |
172 | | * ourselves. I'd have preferred to alter pdf_process_string, but that |
173 | | * is used in many other places, and those places rely on this behaviour. |
174 | | */ |
175 | 0 | if (pte->text.operation & TEXT_DO_NONE) { |
176 | 0 | pte->returned.total_width.x = total_width.x = out.returned.total_width.x; |
177 | 0 | pte->returned.total_width.y = total_width.y = out.returned.total_width.y; |
178 | 0 | } else { |
179 | 0 | pte->returned.total_width.x = total_width.x += |
180 | 0 | out.returned.total_width.x; |
181 | 0 | pte->returned.total_width.y = total_width.y += |
182 | 0 | out.returned.total_width.y; |
183 | 0 | } |
184 | 0 | } |
185 | 0 | pdf_text_release_cgp(penum); |
186 | 0 | } |
187 | 0 | if (font_code == 2) |
188 | 0 | break; |
189 | 0 | buf[0] = (byte)chr; |
190 | 0 | buf_index = 1; |
191 | 0 | space_char = ((pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) && |
192 | 0 | pte->text.space.s_char == char_code ? chr : ~0); |
193 | 0 | psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix; |
194 | 0 | prev_font = new_font; |
195 | 0 | } |
196 | 0 | if (!return_width) |
197 | 0 | return 0; |
198 | 0 | return pdf_shift_text_currentpoint(penum, &total_width); |
199 | 0 | } |
200 | | |
201 | | /* ---------------- CMap-based composite font ---------------- */ |
202 | | |
203 | | /* |
204 | | * Process a text string in a composite font with FMapType == 9 (CMap). |
205 | | */ |
206 | | static const char *const standard_cmap_names[] = { |
207 | | /* The following were added in PDF 1.5. */ |
208 | | |
209 | | "UniGB-UTF16-H", "UniGB-UTF16-V", |
210 | | |
211 | | "GBKp-EUC-H", "GBKp-EUC-V", |
212 | | "HKscs-B5-H", "HKscs-B5-V", |
213 | | "UniCNS-UTF16-H", "UniCNS-UTF16-V", |
214 | | "UniJIS-UTF16-H", "UniJIS-UTF16-V", |
215 | | "UniKS-UTF16-H", "UniKS-UTF16-V", |
216 | 0 | #define END_PDF15_CMAP_NAMES_INDEX 12 |
217 | | /* The following were added in PDF 1.4. */ |
218 | | "GBKp-EUC-H", "GBKp-EUC-V", |
219 | | "GBK2K-H", "GBK2K-V", |
220 | | "HKscs-B5-H", "HKscs-B5-V", |
221 | 0 | #define END_PDF14_CMAP_NAMES_INDEX 18 |
222 | | /* The following were added in PDF 1.3. */ |
223 | | |
224 | | "GBpc-EUC-V", |
225 | | "GBK-EUC-H", "GBK-EUC-V", |
226 | | "UniGB-UCS2-H", "UniGB-UCS2-V", |
227 | | |
228 | | "ETenms-B5-H", "ETenms-B5-V", |
229 | | |
230 | | "UniCNS-UCS2-H", "UniCNS-UCS2-V", |
231 | | |
232 | | "90msp-RKSJ-H", "90msp-RKSJ-V", |
233 | | "EUC-H", "EUC-V", |
234 | | "UniJIS-UCS2-H", "UniJIS-UCS2-V", |
235 | | "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V", |
236 | | |
237 | | "KSCms-UHC-HW-H", "KSCms-UHC-HW-V", |
238 | | "UniKS-UCS2-H", "UniKS-UCS2-V", |
239 | | |
240 | 0 | #define END_PDF13_CMAP_NAMES_INDEX 39 |
241 | | /* The following were added in PDF 1.2. */ |
242 | | |
243 | | "GB-EUC-H", "GB-EUC-V", |
244 | | "GBpc-EUC-H", |
245 | | |
246 | | "B5pc-H", "B5pc-V", |
247 | | "ETen-B5-H", "ETen-B5-V", |
248 | | "CNS-EUC-H", "CNS-EUC-V", |
249 | | |
250 | | "83pv-RKSJ-H", |
251 | | "90ms-RKSJ-H", "90ms-RKSJ-V", |
252 | | "90pv-RKSJ-H", |
253 | | "Add-RKSJ-H", "Add-RKSJ-V", |
254 | | "Ext-RKSJ-H", "Ext-RKSJ-V", |
255 | | "H", "V", |
256 | | |
257 | | "KSC-EUC-H", "KSC-EUC-V", |
258 | | "KSCms-UHC-H", "KSCms-UHC-V", |
259 | | "KSCpc-EUC-H", |
260 | | |
261 | | "Identity-H", "Identity-V", |
262 | | |
263 | | 0 |
264 | | }; |
265 | | |
266 | | static int |
267 | | attach_cmap_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, |
268 | | const gs_cmap_t *pcmap, int font_index_only) |
269 | 1.32k | { |
270 | 1.32k | const char *const *pcmn = |
271 | 1.32k | standard_cmap_names + |
272 | 1.32k | (pdev->CompatibilityLevel < 1.3 ? END_PDF13_CMAP_NAMES_INDEX : |
273 | 1.32k | pdev->CompatibilityLevel < 1.4 ? END_PDF14_CMAP_NAMES_INDEX : |
274 | 1.32k | pdev->CompatibilityLevel < 1.5 ? END_PDF15_CMAP_NAMES_INDEX : 0); |
275 | 1.32k | bool is_identity = false; |
276 | 1.32k | pdf_resource_t *pcmres = 0; /* CMap */ |
277 | 1.32k | int code; |
278 | | |
279 | | /* Make sure cmap names is properly initialised. Silences Coverity warning */ |
280 | 1.32k | if (!pcmn) |
281 | 0 | return_error(gs_error_unknownerror); |
282 | | |
283 | | /* |
284 | | * If the CMap isn't standard, write it out if necessary. |
285 | | */ |
286 | 84.2k | for (; *pcmn != 0; ++pcmn) |
287 | 84.1k | if (pcmap->CMapName.size == strlen(*pcmn) && |
288 | 84.1k | !memcmp(*pcmn, pcmap->CMapName.data, pcmap->CMapName.size)) |
289 | 1.26k | break; |
290 | | |
291 | | /* For PDF/A we need to write out all non-identity CMaps |
292 | | * first force the identity check. |
293 | | */ |
294 | 1.32k | if (*pcmn == 0 || pdev->PDFA != 0) { |
295 | | /* |
296 | | * PScript5.dll Version 5.2 creates identity CMaps with |
297 | | * instandard name. Check this specially here |
298 | | * and later replace with a standard name. |
299 | | * This is a temporary fix for SF bug #615994 "CMAP is corrupt". |
300 | | */ |
301 | 69 | is_identity = gs_cmap_is_identity(pcmap, font_index_only); |
302 | 69 | } |
303 | | /* If the CMap is non-standard, or we are producing PDF/A, and its not |
304 | | * an Identity CMap, then we need to emit it. |
305 | | */ |
306 | 1.32k | if ((*pcmn == 0 || pdev->PDFA != 0) && !is_identity) { /* not standard */ |
307 | 60 | pcmres = pdf_find_resource_by_gs_id(pdev, resourceCMap, pcmap->id + font_index_only); |
308 | 60 | if (pcmres == 0) { |
309 | | /* Create and write the CMap object. */ |
310 | 60 | code = pdf_cmap_alloc(pdev, pcmap, &pcmres, font_index_only); |
311 | 60 | if (code < 0) |
312 | 0 | return code; |
313 | 60 | } |
314 | 60 | } |
315 | 1.32k | if (pcmap->from_Unicode) { |
316 | 0 | gs_cmap_ranges_enum_t renum; |
317 | |
|
318 | 0 | gs_cmap_ranges_enum_init(pcmap, &renum); |
319 | 0 | if (gs_cmap_enum_next_range(&renum) == 0 && renum.range.size == 2 && |
320 | 0 | gs_cmap_enum_next_range(&renum) == 1) { |
321 | | /* |
322 | | * Exactly one code space range, of size 2. Add an identity |
323 | | * ToUnicode CMap. |
324 | | */ |
325 | 0 | if (!pdev->Identity_ToUnicode_CMaps[pcmap->WMode]) { |
326 | | /* Create and write an identity ToUnicode CMap now. */ |
327 | 0 | gs_cmap_t *pidcmap; |
328 | |
|
329 | 0 | code = gs_cmap_create_char_identity(&pidcmap, 2, pcmap->WMode, |
330 | 0 | pdev->memory); |
331 | 0 | if (code < 0) |
332 | 0 | return code; |
333 | 0 | pidcmap->CMapType = 2; /* per PDF Reference */ |
334 | 0 | pidcmap->ToUnicode = true; |
335 | 0 | code = pdf_cmap_alloc(pdev, pidcmap, |
336 | 0 | &pdev->Identity_ToUnicode_CMaps[pcmap->WMode], -1); |
337 | 0 | if (code < 0) |
338 | 0 | return code; |
339 | 0 | } |
340 | 0 | pdfont->res_ToUnicode = pdev->Identity_ToUnicode_CMaps[pcmap->WMode]; |
341 | 0 | } |
342 | 0 | } |
343 | 1.32k | if (pcmres || is_identity) { |
344 | 69 | if (pdfont->u.type0.CMapName_data == NULL || pcmap->CMapName.size != pdfont->u.type0.CMapName_size || |
345 | 69 | memcmp(pdfont->u.type0.CMapName_data, pcmap->CMapName.data, pcmap->CMapName.size)) |
346 | 0 | { |
347 | 0 | byte *chars = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, pcmap->CMapName.size, |
348 | 0 | "pdf_font_resource_t(CMapName)"); |
349 | |
|
350 | 0 | if (chars == 0) |
351 | 0 | return_error(gs_error_VMerror); |
352 | 0 | memcpy(chars, pcmap->CMapName.data, pcmap->CMapName.size); |
353 | 0 | if (pdfont->u.type0.CMapName_data != NULL) |
354 | 0 | gs_free_object(pdev->pdf_memory->non_gc_memory, pdfont->u.type0.CMapName_data, "rewriting CMapName"); |
355 | 0 | pdfont->u.type0.CMapName_data = chars; |
356 | 0 | pdfont->u.type0.CMapName_size = pcmap->CMapName.size; |
357 | 0 | } |
358 | 69 | if (is_identity) |
359 | 9 | strcpy(pdfont->u.type0.Encoding_name, |
360 | 9 | (pcmap->WMode ? "/Identity-V" : "/Identity-H")); |
361 | 60 | else |
362 | 60 | gs_snprintf(pdfont->u.type0.Encoding_name, sizeof(pdfont->u.type0.Encoding_name), |
363 | 60 | "%"PRId64" 0 R", pdf_resource_id(pcmres)); |
364 | 1.26k | } else { |
365 | 1.26k | uint size = 0; |
366 | | |
367 | 1.26k | if (!*pcmn) |
368 | | /* Should not be possible, if *pcmn is NULL then either |
369 | | * is_identity is true or we create pcmres. |
370 | | */ |
371 | 0 | return_error(gs_error_invalidfont); |
372 | | |
373 | 1.26k | size = strlen(*pcmn); |
374 | 1.26k | if (pdfont->u.type0.CMapName_data == NULL || size != pdfont->u.type0.CMapName_size || |
375 | 1.26k | memcmp(pdfont->u.type0.CMapName_data, *pcmn, size) != 0) |
376 | 0 | { |
377 | 0 | byte *chars = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, size, "pdf_font_resource_t(CMapName)"); |
378 | 0 | if (chars == 0) |
379 | 0 | return_error(gs_error_VMerror); |
380 | | |
381 | 0 | memcpy(chars, *pcmn, size); |
382 | |
|
383 | 0 | if (pdfont->u.type0.CMapName_data != NULL) |
384 | 0 | gs_free_object(pdev->pdf_memory->non_gc_memory, pdfont->u.type0.CMapName_data, "rewriting CMapName"); |
385 | 0 | pdfont->u.type0.CMapName_data = chars; |
386 | 0 | pdfont->u.type0.CMapName_size = size; |
387 | 0 | } |
388 | | |
389 | 1.26k | gs_snprintf(pdfont->u.type0.Encoding_name, sizeof(pdfont->u.type0.Encoding_name), "/%s", *pcmn); |
390 | 1.26k | pdfont->u.type0.cmap_is_standard = true; |
391 | 1.26k | } |
392 | 1.32k | pdfont->u.type0.WMode = pcmap->WMode; |
393 | 1.32k | return 0; |
394 | 1.32k | } |
395 | | |
396 | | static int estimate_fontbbox(pdf_text_enum_t *pte, gs_font_base *font, |
397 | | const gs_matrix *pfmat, |
398 | | gs_rect *text_bbox) |
399 | 0 | { |
400 | 0 | gs_matrix m; |
401 | 0 | gs_point p0, p1, p2, p3; |
402 | |
|
403 | 0 | if (font->FontBBox.p.x == font->FontBBox.q.x || |
404 | 0 | font->FontBBox.p.y == font->FontBBox.q.y) |
405 | 0 | return_error(gs_error_undefined); |
406 | 0 | if (pfmat == 0) |
407 | 0 | pfmat = &font->FontMatrix; |
408 | 0 | m = ctm_only(pte->pgs); |
409 | 0 | m.tx = fixed2float(pte->origin.x); |
410 | 0 | m.ty = fixed2float(pte->origin.y); |
411 | 0 | gs_matrix_multiply(pfmat, &m, &m); |
412 | |
|
413 | 0 | gs_point_transform(font->FontBBox.p.x, font->FontBBox.p.y, &m, &p0); |
414 | 0 | gs_point_transform(font->FontBBox.p.x, font->FontBBox.q.y, &m, &p1); |
415 | 0 | gs_point_transform(font->FontBBox.q.x, font->FontBBox.p.y, &m, &p2); |
416 | 0 | gs_point_transform(font->FontBBox.q.x, font->FontBBox.q.y, &m, &p3); |
417 | 0 | text_bbox->p.x = min(min(p0.x, p1.x), min(p1.x, p2.x)); |
418 | 0 | text_bbox->p.y = min(min(p0.y, p1.y), min(p1.y, p2.y)); |
419 | 0 | text_bbox->q.x = max(max(p0.x, p1.x), max(p1.x, p2.x)); |
420 | 0 | text_bbox->q.y = max(max(p0.y, p1.y), max(p1.y, p2.y)); |
421 | |
|
422 | 0 | return 0; |
423 | 0 | } |
424 | | |
425 | | /* Record widths and CID => GID mappings. */ |
426 | | static int |
427 | | scan_cmap_text(pdf_text_enum_t *pte, void *vbuf) |
428 | 364k | { |
429 | 364k | gx_device_pdf *pdev = (gx_device_pdf *)pte->dev; |
430 | | /* gs_font_type0 *const font = (gs_font_type0 *)pte->current_font;*/ /* Type 0, fmap_CMap */ |
431 | 364k | gs_font_type0 *const font = (gs_font_type0 *)pte->orig_font; /* Type 0, fmap_CMap */ |
432 | | /* Not sure. Changed for CDevProc callout. Was pte->current_font */ |
433 | 364k | gs_text_enum_t scan = *(gs_text_enum_t *)pte; |
434 | 364k | int wmode = font->WMode == 0 ? 0 : 1, code, rcode = 0; |
435 | 364k | pdf_font_resource_t *pdsubf0 = NULL; |
436 | 364k | gs_font *subfont0 = NULL, *saved_subfont = NULL; |
437 | 364k | uint index = scan.index, xy_index = scan.xy_index, start_index = index; |
438 | 364k | uint font_index0 = 0x7badf00d; |
439 | 364k | bool done = false; |
440 | 364k | pdf_char_glyph_pairs_t p; |
441 | 364k | gs_glyph *type1_glyphs = (gs_glyph *)vbuf; |
442 | 364k | int num_type1_glyphs = 0; |
443 | | |
444 | 364k | p.num_all_chars = 1; |
445 | 364k | p.num_unused_chars = 1; |
446 | 364k | p.unused_offset = 0; |
447 | 364k | pte->returned.total_width.x = pte->returned.total_width.y = 0;; |
448 | 364k | for (;;) { |
449 | 364k | uint break_index, break_xy_index; |
450 | 364k | uint font_index = 0x7badf00d; |
451 | 364k | gs_const_string str; |
452 | 364k | pdf_text_process_state_t text_state; |
453 | 364k | pdf_font_resource_t *pdsubf = NULL; |
454 | 364k | gs_font *subfont = NULL; |
455 | 364k | gs_point wxy; |
456 | 364k | bool font_change = 0; |
457 | 364k | gx_path *path = gs_text_enum_path(pte); |
458 | | |
459 | 364k | code = gx_path_current_point(path, &pte->origin); |
460 | 364k | if (code < 0) |
461 | 0 | return code; |
462 | 642k | do { |
463 | 642k | gs_char chr; |
464 | 642k | gs_glyph glyph; |
465 | 642k | pdf_font_descriptor_t *pfd; |
466 | 642k | byte *glyph_usage; |
467 | 642k | double *real_widths, *w, *v, *w0; |
468 | 642k | int char_cache_size, width_cache_size; |
469 | 642k | gs_char cid; |
470 | | |
471 | 642k | break_index = scan.index; |
472 | 642k | break_xy_index = scan.xy_index; |
473 | 642k | code = font->procs.next_char_glyph(&scan, &chr, &glyph); |
474 | 642k | if (code == 2) { /* end of string */ |
475 | 114k | if (subfont == NULL) |
476 | 153 | subfont = scan.fstack.items[scan.fstack.depth].font; |
477 | 114k | done = true; |
478 | 114k | break; |
479 | 114k | } |
480 | 528k | if (code < 0) |
481 | 3 | return code; |
482 | 528k | subfont = scan.fstack.items[scan.fstack.depth].font; |
483 | 528k | font_index = scan.fstack.items[scan.fstack.depth - 1].index; |
484 | 528k | scan.xy_index++; |
485 | 528k | if (glyph == GS_NO_GLYPH) |
486 | 0 | glyph = GS_MIN_CID_GLYPH; |
487 | 528k | cid = glyph - GS_MIN_CID_GLYPH; |
488 | 528k | switch (subfont->FontType) { |
489 | 0 | case ft_encrypted: |
490 | 0 | case ft_encrypted2:{ |
491 | 0 | if (glyph == GS_MIN_CID_GLYPH) { |
492 | 0 | glyph = subfont->procs.encode_char(subfont, chr, GLYPH_SPACE_NAME); |
493 | 0 | } |
494 | 0 | type1_glyphs[num_type1_glyphs] = glyph; |
495 | 0 | num_type1_glyphs++; |
496 | 0 | break; |
497 | 0 | } |
498 | 11.4k | case ft_CID_encrypted: |
499 | 528k | case ft_CID_TrueType: { |
500 | 528k | p.s[0].glyph = glyph; |
501 | 528k | p.s[0].chr = cid; |
502 | 528k | code = pdf_obtain_cidfont_resource(pdev, subfont, &pdsubf, &p); |
503 | 528k | if (code < 0) |
504 | 248k | return code; |
505 | 279k | break; |
506 | 528k | } |
507 | 279k | case ft_user_defined: |
508 | 0 | case ft_PDF_user_defined: |
509 | 0 | { |
510 | 0 | gs_string str1; |
511 | |
|
512 | 0 | str1.data = NULL; |
513 | 0 | str1.size = 0; |
514 | 0 | pte->current_font = subfont; |
515 | 0 | code = pdf_obtain_font_resource(pte, &str1, &pdsubf); |
516 | 0 | if (code < 0) |
517 | 0 | return code; |
518 | 0 | cid = pdf_find_glyph(pdsubf, glyph); |
519 | 0 | if (cid == GS_NO_CHAR) { |
520 | 0 | code = pdf_make_font3_resource(pdev, subfont, &pdsubf); |
521 | 0 | if (code < 0) |
522 | 0 | return code; |
523 | 0 | code = pdf_attach_font_resource(pdev, subfont, pdsubf); |
524 | 0 | if (code < 0) |
525 | 0 | return code; |
526 | 0 | cid = 0; |
527 | 0 | } |
528 | 0 | break; |
529 | 0 | } |
530 | 0 | default: |
531 | | /* An unsupported case, fall back to default implementation. */ |
532 | 0 | return_error(gs_error_rangecheck); |
533 | 528k | } |
534 | 279k | code = pdf_attached_font_resource(pdev, (gs_font *)subfont, &pdsubf, |
535 | 279k | &glyph_usage, &real_widths, &char_cache_size, &width_cache_size); |
536 | 279k | if (code < 0) |
537 | 0 | return code; |
538 | 279k | if (break_index > start_index && pdev->charproc_just_accumulated) |
539 | 0 | break; |
540 | 279k | if ((subfont->FontType == ft_user_defined || subfont->FontType == ft_PDF_user_defined )&& |
541 | 279k | (break_index > start_index || !pdev->charproc_just_accumulated) && |
542 | 279k | !(pdsubf->u.simple.s.type3.cached[cid >> 3] & (0x80 >> (cid & 7)))) { |
543 | 0 | if (subfont0 && subfont0->FontType != ft_user_defined && subfont0->FontType != ft_PDF_user_defined) |
544 | | /* This is hacky. By pretending to be in a type 3 font doing a charpath we force |
545 | | * text handling to fall right back to bitmap glyphs. This is because we can't handle |
546 | | * CIDFonts with mixed type 1/3 descendants. Ugly but it produces correct output for |
547 | | * what is after all a dumb setup. |
548 | | */ |
549 | 0 | pdev->type3charpath = 1; |
550 | 0 | pte->current_font = subfont; |
551 | 0 | return_error(gs_error_undefined); |
552 | 0 | } |
553 | 279k | if (subfont->FontType == ft_encrypted || subfont->FontType == ft_encrypted2) { |
554 | 0 | font_change = (subfont != subfont0 && subfont0 != NULL); |
555 | 0 | if (font_change) { |
556 | 0 | saved_subfont = subfont; |
557 | 0 | subfont = subfont0; |
558 | 0 | num_type1_glyphs--; |
559 | 0 | } |
560 | 0 | } else |
561 | 279k | font_change = (pdsubf != pdsubf0 && pdsubf0 != NULL); |
562 | 279k | if (!font_change) { |
563 | 279k | pdsubf0 = pdsubf; |
564 | 279k | font_index0 = font_index; |
565 | 279k | subfont0 = subfont; |
566 | 279k | } |
567 | 279k | if (subfont->FontType != ft_encrypted && subfont->FontType != ft_encrypted2) { |
568 | 279k | pfd = pdsubf->FontDescriptor; |
569 | 279k | code = pdf_resize_resource_arrays(pdev, pdsubf, cid + 1); |
570 | 279k | if (code < 0) |
571 | 2 | return code; |
572 | 279k | if (subfont->FontType == ft_CID_encrypted || subfont->FontType == ft_CID_TrueType) { |
573 | 279k | if (cid >=width_cache_size) { |
574 | | /* fixme: we add the CID=0 glyph as CID=cid glyph to the output font. |
575 | | Really it must not add and leave the CID undefined. */ |
576 | 3.68k | cid = 0; /* notdef. */ |
577 | 3.68k | } |
578 | 279k | } |
579 | 279k | if (cid >= char_cache_size || cid >= width_cache_size) |
580 | 0 | return_error(gs_error_unregistered); /* Must not happen */ |
581 | 279k | if (pdsubf->FontType == ft_user_defined || pdsubf->FontType == ft_PDF_user_defined || pdsubf->FontType == ft_encrypted || |
582 | 279k | pdsubf->FontType == ft_encrypted2) { |
583 | 279k | } else { |
584 | 279k | pdf_font_resource_t *pdfont; |
585 | 279k | bool notdef_subst = false; |
586 | | |
587 | 279k | code = pdf_obtain_cidfont_widths_arrays(pdev, pdsubf, wmode, &w, &w0, &v); |
588 | 279k | if (code < 0) |
589 | 0 | return code; |
590 | 279k | code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf, font_index, |
591 | 279k | &font->data.CMap->CMapName, &pdfont); |
592 | 279k | if (code < 0) |
593 | 0 | return code; |
594 | 279k | if (pdf_is_CID_font(subfont)) { |
595 | | /* Some Pscript5 output has non-identity mappings between character code and CID |
596 | | * and the GlyphNames2Unicode dictionary uses character codes, not glyph names. So |
597 | | * if we detect ths condition we cheat and claim not to be a CIDFont, so that the |
598 | | * decode_glyph procedure can use the character code to look up the GlyphNames2Unicode |
599 | | * dictionary. See bugs #696021, #688768 and #687954 for examples of the various ways |
600 | | * this code can be exercised. |
601 | | */ |
602 | 279k | if (chr == glyph - GS_MIN_CID_GLYPH) |
603 | 273k | code = subfont->procs.decode_glyph((gs_font *)subfont, glyph, -1, NULL, 0); |
604 | 6.07k | else |
605 | 6.07k | code = subfont->procs.decode_glyph((gs_font *)subfont, glyph, chr, NULL, 0); |
606 | 279k | if (code != 0) |
607 | | /* Since PScript5.dll creates GlyphNames2Unicode with character codes |
608 | | instead CIDs, and with the WinCharSetFFFF-H2 CMap |
609 | | character codes appears different than CIDs (Bug 687954), |
610 | | pass the character code intead the CID. */ |
611 | 896 | code = pdf_add_ToUnicode(pdev, subfont, pdfont, |
612 | 896 | chr + GS_MIN_CID_GLYPH, chr, NULL); |
613 | 278k | else { |
614 | | /* If we interpret a PDF document, ToUnicode |
615 | | CMap may be attached to the Type 0 font. */ |
616 | 278k | code = pdf_add_ToUnicode(pdev, pte->orig_font, pdfont, |
617 | 278k | chr + GS_MIN_CID_GLYPH, chr, NULL); |
618 | 278k | } |
619 | 279k | } |
620 | 0 | else |
621 | 0 | code = pdf_add_ToUnicode(pdev, subfont, pdfont, glyph, cid, NULL); |
622 | 279k | if (code < 0) |
623 | 0 | return code; |
624 | | /* We can't check pdsubf->used[cid >> 3] here, |
625 | | because it mixed data for different values of WMode. |
626 | | Perhaps pdf_font_used_glyph returns fast with reused glyphs. |
627 | | */ |
628 | 279k | code = pdf_font_used_glyph(pfd, glyph, (gs_font_base *)subfont); |
629 | 279k | if (code == gs_error_rangecheck) { |
630 | 4.07k | if (!(pdsubf->used[cid >> 3] & (0x80 >> (cid & 7)))) { |
631 | 403 | char buf[gs_font_name_max + 1]; |
632 | 403 | int l = min(sizeof(buf) - 1, subfont->font_name.size); |
633 | | |
634 | 403 | memcpy(buf, subfont->font_name.chars, l); |
635 | 403 | buf[l] = 0; |
636 | 403 | emprintf3(pdev->memory, |
637 | 403 | "Missing glyph CID=%d, glyph=%04x in the font %s . The output PDF may fail with some viewers.\n", |
638 | 403 | (int)cid, |
639 | 403 | (unsigned int)(glyph - GS_MIN_CID_GLYPH), |
640 | 403 | buf); |
641 | 403 | pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7); |
642 | 403 | if (pdev->PDFA != 0) { |
643 | 0 | switch (pdev->PDFACompatibilityPolicy) { |
644 | | /* Default behaviour matches Adobe Acrobat, warn and continue, |
645 | | * output file will not be PDF/A compliant |
646 | | */ |
647 | 0 | case 0: |
648 | 0 | case 1: |
649 | 0 | case 3: |
650 | 0 | emprintf(pdev->memory, |
651 | 0 | "All used glyphs mst be present in fonts for PDF/A, reverting to normal PDF output.\n"); |
652 | 0 | pdev->AbortPDFAX = true; |
653 | 0 | pdev->PDFA = 0; |
654 | 0 | break; |
655 | 0 | case 2: |
656 | 0 | emprintf(pdev->memory, |
657 | 0 | "All used glyphs mst be present in fonts for PDF/A, aborting conversion.\n"); |
658 | 0 | return_error(gs_error_invalidfont); |
659 | 0 | break; |
660 | 0 | default: |
661 | 0 | emprintf(pdev->memory, |
662 | 0 | "All used glyphs mst be present in fonts for PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n"); |
663 | 0 | pdev->AbortPDFAX = true; |
664 | 0 | pdev->PDFA = 0; |
665 | 0 | break; |
666 | 0 | } |
667 | 0 | } |
668 | 403 | } |
669 | 4.07k | cid = 0, code = 1; /* undefined glyph. */ |
670 | 4.07k | notdef_subst = true; |
671 | | /* If this is the first use of CID=0, get its width */ |
672 | 4.07k | if (pdsubf->Widths[cid] == 0) { |
673 | 3.98k | pdf_glyph_widths_t widths; |
674 | | |
675 | 3.98k | code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths, |
676 | 3.98k | pte->cdevproc_callout ? pte->cdevproc_result : NULL); |
677 | 3.98k | } |
678 | 275k | } else if (code < 0) |
679 | 702 | return code; |
680 | 278k | if (glyph == GS_MIN_CID_GLYPH && pdev->PDFA != 0) { |
681 | 0 | switch (pdev->PDFACompatibilityPolicy) { |
682 | 0 | case 0: |
683 | 0 | case 1: |
684 | 0 | case 3: |
685 | 0 | emprintf(pdev->memory, |
686 | 0 | "A CIDFont uses CID 0, which is not legal for PDF/A, reverting to normal PDF output.\n"); |
687 | 0 | pdev->AbortPDFAX = true; |
688 | 0 | pdev->PDFA = 0; |
689 | 0 | break; |
690 | 0 | case 2: |
691 | 0 | emprintf(pdev->memory, |
692 | 0 | "A CIDFont uses CID 0, which is not legal for PDF/A, aborting conversion.\n"); |
693 | 0 | return_error(gs_error_invalidfont); |
694 | 0 | break; |
695 | 0 | default: |
696 | 0 | emprintf(pdev->memory, |
697 | 0 | "A CIDFont uses CID 0, which is not legal for PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n"); |
698 | 0 | pdev->AbortPDFAX = true; |
699 | 0 | pdev->PDFA = 0; |
700 | 0 | break; |
701 | 0 | } |
702 | 0 | } |
703 | 278k | if ((code == 0 /* just copied */ || pdsubf->Widths[cid] == 0) && !notdef_subst) { |
704 | 274k | pdf_glyph_widths_t widths; |
705 | | |
706 | 274k | code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths, |
707 | 274k | pte->cdevproc_callout ? pte->cdevproc_result : NULL); |
708 | 274k | if (code < 0) |
709 | 0 | return code; |
710 | 274k | if (code == TEXT_PROCESS_CDEVPROC) { |
711 | 0 | pte->returned.current_glyph = glyph; |
712 | 0 | pte->current_font = subfont; |
713 | 0 | rcode = TEXT_PROCESS_CDEVPROC; |
714 | 0 | break; |
715 | 0 | } |
716 | 274k | if (code >= 0) { |
717 | 274k | if (cid > pdsubf->count) |
718 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
719 | 274k | w[cid] = widths.Width.w; |
720 | 274k | if (v != NULL) { |
721 | 750 | v[cid * 2 + 0] = widths.Width.v.x; |
722 | 750 | v[cid * 2 + 1] = widths.Width.v.y; |
723 | 750 | } |
724 | 274k | real_widths[cid] = widths.real_width.w; |
725 | 274k | } |
726 | 274k | if (wmode) { |
727 | | /* Since AR5 use W or DW to compute the x-coordinate of |
728 | | v-vector, comupte and store the glyph width for WMode 0. */ |
729 | | /* fixme : skip computing real_width here. */ |
730 | 750 | code = pdf_glyph_widths(pdsubf, 0, glyph, (gs_font *)subfont, &widths, |
731 | 750 | pte->cdevproc_callout ? pte->cdevproc_result : NULL); |
732 | 750 | if (code < 0) |
733 | 0 | return code; |
734 | 750 | w0[cid] = widths.Width.w; |
735 | 750 | } |
736 | 274k | if (pdsubf->u.cidfont.CIDToGIDMap != 0) { |
737 | 268k | uint gid = 0; |
738 | 268k | gs_font_cid2 *subfont2 = (gs_font_cid2 *)subfont; |
739 | | |
740 | 268k | gid = subfont2->cidata.CIDMap_proc(subfont2, glyph); |
741 | | |
742 | | /* If this is a TrueType CIDFont, check the GSUB table to see if there's |
743 | | * a suitable substitute glyph. |
744 | | */ |
745 | 268k | if (subfont2->FontType == ft_CID_TrueType) |
746 | 268k | gid = subfont2->data.substitute_glyph_index_vertical((gs_font_type42 *)subfont, gid, subfont2->WMode, glyph); |
747 | 268k | pdsubf->u.cidfont.CIDToGIDMap[cid] = gid; |
748 | 268k | } |
749 | 274k | } |
750 | 278k | if (wmode) |
751 | 1.38k | pdsubf->u.cidfont.used2[cid >> 3] |= 0x80 >> (cid & 7); |
752 | 278k | } |
753 | 278k | pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7); |
754 | 278k | } |
755 | 278k | if (pte->cdevproc_callout) { |
756 | | /* Only handle a single character because its width is stored |
757 | | into pte->cdevproc_result, and process_text_modify_width neds it. |
758 | | fixme: next time take from w, v, real_widths. */ |
759 | 0 | break_index = scan.index; |
760 | 0 | break_xy_index = scan.xy_index; |
761 | 0 | break; |
762 | 0 | } |
763 | 278k | } while (!font_change); |
764 | 114k | if (break_index > index) { |
765 | 114k | pdf_font_resource_t *pdfont; |
766 | 114k | gs_matrix m3; |
767 | 114k | int xy_index_step = (!(pte->text.operation & TEXT_REPLACE_WIDTHS) ? 0 : |
768 | 114k | pte->text.x_widths == pte->text.y_widths ? 2 : 1); |
769 | 114k | gs_text_params_t save_text; |
770 | | |
771 | 114k | if (!subfont && num_type1_glyphs != 0) |
772 | 0 | subfont = subfont0; |
773 | 114k | if (subfont && (subfont->FontType == ft_encrypted || subfont->FontType == ft_encrypted2)) { |
774 | 0 | int save_op = pte->text.operation; |
775 | 0 | gs_font *save_font = pte->current_font; |
776 | 0 | const gs_glyph *save_data = pte->text.data.glyphs; |
777 | |
|
778 | 0 | pte->current_font = subfont; |
779 | 0 | pte->text.operation |= TEXT_FROM_GLYPHS; |
780 | 0 | pte->text.data.glyphs = type1_glyphs; |
781 | 0 | str.data = ((const byte *)vbuf) + ((pte->text.size - pte->index) * sizeof(gs_glyph)); |
782 | 0 | str.size = num_type1_glyphs; |
783 | 0 | code = pdf_obtain_font_resource_unencoded(pte, (const gs_string *)&str, &pdsubf0, |
784 | 0 | type1_glyphs); |
785 | 0 | if (code < 0) { |
786 | | /* Replace the modified values, fall back to default implementation |
787 | | * (type 3 bitmap image font) |
788 | | */ |
789 | 0 | pte->current_font = save_font; |
790 | 0 | pte->text.operation |= save_op; |
791 | 0 | pte->text.data.glyphs = save_data; |
792 | 0 | return(code); |
793 | 0 | } |
794 | 0 | memcpy((void *)scan.text.data.bytes, (void *)str.data, str.size); |
795 | 0 | str.data = scan.text.data.bytes; |
796 | 0 | pdsubf = pdsubf0; |
797 | 0 | pte->text.operation = save_op; |
798 | 0 | pte->text.data.glyphs = save_data; |
799 | 0 | } |
800 | 114k | if (!subfont0 || !pdsubf0) |
801 | | /* This should be impossible */ |
802 | 0 | return_error(gs_error_invalidfont); |
803 | | |
804 | 114k | pte->current_font = subfont0; |
805 | 114k | code = gs_matrix_multiply(&subfont0->FontMatrix, &font->FontMatrix, &m3); |
806 | | /* We thought that it should be gs_matrix_multiply(&font->FontMatrix, &subfont0->FontMatrix, &m3); */ |
807 | 114k | if (code < 0) |
808 | 0 | return code; |
809 | 114k | if (pdsubf0->FontType == ft_user_defined || pdsubf0->FontType == ft_PDF_user_defined || pdsubf0->FontType == ft_encrypted || |
810 | 114k | pdsubf0->FontType == ft_encrypted2) |
811 | 0 | pdfont = pdsubf0; |
812 | 114k | else { |
813 | 114k | code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf0, font_index0, |
814 | 114k | &font->data.CMap->CMapName, &pdfont); |
815 | 114k | if (code < 0) |
816 | 0 | return code; |
817 | 114k | if (!pdfont->u.type0.Encoding_name[0]) { |
818 | | /* |
819 | | * If pdfont->u.type0.Encoding_name is set, |
820 | | * a CMap resource is already attached. |
821 | | * See attach_cmap_resource. |
822 | | */ |
823 | 1.32k | code = attach_cmap_resource(pdev, pdfont, font->data.CMap, font_index0); |
824 | 1.32k | if (code < 0) |
825 | 0 | return code; |
826 | 1.32k | } |
827 | 114k | } |
828 | 114k | pdf_set_text_wmode(pdev, font->WMode); |
829 | 114k | code = pdf_update_text_state(&text_state, (pdf_text_enum_t *)pte, pdfont, &m3); |
830 | 114k | if (code < 0) |
831 | 0 | return code; |
832 | | /* process_text_modify_width breaks text parameters. |
833 | | We would like to improve it someday. |
834 | | Now save them locally and restore after the call. */ |
835 | 114k | save_text = pte->text; |
836 | 114k | if (subfont && (subfont->FontType != ft_encrypted && |
837 | 114k | subfont->FontType != ft_encrypted2)) { |
838 | | /* If we are a type 1 descendant, we already sorted this out above */ |
839 | 114k | str.data = scan.text.data.bytes + index; |
840 | 114k | str.size = break_index - index; |
841 | 114k | } |
842 | 114k | if (pte->text.operation & TEXT_REPLACE_WIDTHS) { |
843 | 0 | if (pte->text.x_widths != NULL) |
844 | 0 | pte->text.x_widths += xy_index * xy_index_step; |
845 | 0 | if (pte->text.y_widths != NULL) |
846 | 0 | pte->text.y_widths += xy_index * xy_index_step; |
847 | 0 | } |
848 | 114k | pte->xy_index = 0; |
849 | 114k | if (subfont && (subfont->FontType == ft_encrypted || |
850 | 114k | subfont->FontType == ft_encrypted2)) { |
851 | 0 | gs_font *f = pte->orig_font; |
852 | |
|
853 | 0 | adjust_first_last_char(pdfont, (byte *)str.data, str.size); |
854 | | |
855 | | /* Make sure we use the descendant font, not the original type 0 ! */ |
856 | 0 | pte->orig_font = subfont; |
857 | 0 | code = process_text_modify_width((pdf_text_enum_t *)pte, |
858 | 0 | (gs_font *)subfont, &text_state, &str, &wxy, type1_glyphs, false, scan.index - index); |
859 | 0 | if (code < 0) |
860 | 0 | return(code); |
861 | 0 | if(font_change) { |
862 | 0 | type1_glyphs[0] = type1_glyphs[num_type1_glyphs]; |
863 | 0 | num_type1_glyphs = 1; |
864 | 0 | subfont = saved_subfont; |
865 | 0 | } else { |
866 | 0 | num_type1_glyphs = 0; |
867 | 0 | } |
868 | 0 | pte->orig_font = f; |
869 | 114k | } else { |
870 | 114k | code = process_text_modify_width((pdf_text_enum_t *)pte, (gs_font *)font, |
871 | 114k | &text_state, &str, &wxy, NULL, true, scan.index - index); |
872 | 114k | } |
873 | 114k | if (pte->text.operation & TEXT_REPLACE_WIDTHS) { |
874 | 0 | if (pte->text.x_widths != NULL) |
875 | 0 | pte->text.x_widths -= xy_index * xy_index_step; |
876 | 0 | if (pte->text.y_widths != NULL) |
877 | 0 | pte->text.y_widths -= xy_index * xy_index_step; |
878 | 0 | } |
879 | 114k | pte->text = save_text; |
880 | 114k | pte->cdevproc_callout = false; |
881 | 114k | if (code < 0) { |
882 | 0 | pte->index = index; |
883 | 0 | pte->xy_index = xy_index; |
884 | 0 | return code; |
885 | 0 | } |
886 | 114k | pte->index = break_index; |
887 | 114k | pte->xy_index = break_xy_index; |
888 | 114k | if (pdev->Eps2Write) { |
889 | 0 | gs_rect text_bbox; |
890 | 0 | gx_device_clip cdev; |
891 | 0 | gx_drawing_color devc; |
892 | 0 | fixed x0, y0, bx2, by2; |
893 | |
|
894 | 0 | text_bbox.q.x = text_bbox.p.y = text_bbox.q.y = 0; |
895 | 0 | estimate_fontbbox(pte, (gs_font_base *)font, NULL, &text_bbox); |
896 | 0 | text_bbox.p.x = fixed2float(pte->origin.x); |
897 | 0 | text_bbox.q.x = text_bbox.p.x + wxy.x; |
898 | |
|
899 | 0 | x0 = float2fixed(text_bbox.p.x); |
900 | 0 | y0 = float2fixed(text_bbox.p.y); |
901 | 0 | bx2 = float2fixed(text_bbox.q.x) - x0; |
902 | 0 | by2 = float2fixed(text_bbox.q.y) - y0; |
903 | |
|
904 | 0 | pdev->AccumulatingBBox++; |
905 | 0 | gx_make_clip_device_on_stack(&cdev, pte->pcpath, (gx_device *)pdev); |
906 | 0 | set_nonclient_dev_color(&devc, gx_device_black((gx_device *)pdev)); /* any non-white color will do */ |
907 | 0 | gx_default_fill_triangle((gx_device *) pdev, x0, y0, |
908 | 0 | float2fixed(text_bbox.p.x) - x0, |
909 | 0 | float2fixed(text_bbox.q.y) - y0, |
910 | 0 | bx2, by2, &devc, lop_default); |
911 | 0 | gx_default_fill_triangle((gx_device *) & cdev, x0, y0, |
912 | 0 | float2fixed(text_bbox.q.x) - x0, |
913 | 0 | float2fixed(text_bbox.p.y) - y0, |
914 | 0 | bx2, by2, &devc, lop_default); |
915 | 0 | gx_destroy_clip_device_on_stack(&cdev); |
916 | 0 | pdev->AccumulatingBBox--; |
917 | 0 | } |
918 | 114k | code = pdf_shift_text_currentpoint(pte, &wxy); |
919 | 114k | if (code < 0) |
920 | 0 | return code; |
921 | 114k | } |
922 | 114k | pdf_text_release_cgp(pte); |
923 | 114k | index = break_index; |
924 | 114k | xy_index = break_xy_index; |
925 | 114k | if (done || rcode != 0) |
926 | 114k | break; |
927 | 89 | pdsubf0 = pdsubf; |
928 | 89 | font_index0 = font_index; |
929 | 89 | subfont0 = subfont; |
930 | 89 | } |
931 | 114k | pte->index = index; |
932 | 114k | pte->xy_index = xy_index; |
933 | 114k | return rcode; |
934 | 364k | } |
935 | | |
936 | | int |
937 | | process_cmap_text(gs_text_enum_t *penum, void *vbuf, uint bsize) |
938 | 364k | { |
939 | 364k | int code; |
940 | 364k | pdf_text_enum_t *pte = (pdf_text_enum_t *)penum; |
941 | 364k | byte *save; |
942 | 364k | uint start = pte->index; |
943 | | |
944 | 364k | if (pte->text.operation & |
945 | 364k | (TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES)) |
946 | 364k | ) |
947 | 0 | return_error(gs_error_rangecheck); |
948 | 364k | if (pte->text.operation & TEXT_INTERVENE) { |
949 | | /* Not implemented. (PostScript doesn't allow TEXT_INTERVENE.) */ |
950 | 0 | return_error(gs_error_rangecheck); |
951 | 0 | } |
952 | | /* scan_cmap_text has the unfortunate side effect of meddling with the |
953 | | * text data in the enumerator. In general that's OK but in the case where |
954 | | * the string is (eg) in a bound procedure, and we run that procedure more |
955 | | * than once, the string is corrupted on the first use and then produces |
956 | | * incorrect output for the subsequent use(s). |
957 | | * The routine is, sadly, extremely convoluted so instead of trying to fix |
958 | | * it so that it doesn't corrupt the string (which looks likely to be impossible |
959 | | * without copying the string at some point) I've chosen to take a copy of the |
960 | | * string here, and restore it after the call to scan_cmap_text. |
961 | | * See bug #695322 and test file Bug691680.ps |
962 | | */ |
963 | 364k | save = (byte *)pte->text.data.bytes; |
964 | 364k | pte->text.data.bytes = gs_alloc_string(pte->memory, pte->text.size, "pdf_text_process"); |
965 | 364k | if (pte->text.data.bytes == NULL) |
966 | 0 | return_error(gs_error_VMerror); |
967 | 364k | memcpy((byte *)pte->text.data.bytes, save, pte->text.size); |
968 | 364k | code = scan_cmap_text(pte, vbuf); |
969 | 364k | gs_free_string(pte->memory, (byte *)pte->text.data.bytes, pte->text.size, "pdf_text_process"); |
970 | 364k | pte->text.data.bytes = save; |
971 | 364k | pte->bytes_decoded = pte->index - start; |
972 | | |
973 | 364k | if (code == TEXT_PROCESS_CDEVPROC) |
974 | 0 | pte->cdevproc_callout = true; |
975 | 364k | else |
976 | 364k | pte->cdevproc_callout = false; |
977 | 364k | return code; |
978 | 364k | } |
979 | | |
980 | | /* ---------------- CIDFont ---------------- */ |
981 | | |
982 | | /* |
983 | | * Process a text string in a CIDFont. (Only glyphshow is supported.) |
984 | | */ |
985 | | int |
986 | | process_cid_text(gs_text_enum_t *pte, void *vbuf, uint bsize) |
987 | 0 | { |
988 | 0 | pdf_text_enum_t *penum = (pdf_text_enum_t *)pte; |
989 | 0 | uint operation = pte->text.operation; |
990 | 0 | gs_text_enum_t save; |
991 | 0 | gs_font *scaled_font = pte->current_font; /* CIDFont */ |
992 | 0 | gs_font *font; /* unscaled font (CIDFont) */ |
993 | 0 | const gs_glyph *glyphs; |
994 | 0 | gs_matrix scale_matrix; |
995 | 0 | pdf_font_resource_t *pdsubf; /* CIDFont */ |
996 | 0 | gs_font_type0 *font0 = NULL; |
997 | 0 | uint size; |
998 | 0 | int code; |
999 | |
|
1000 | 0 | if (operation & TEXT_FROM_GLYPHS) { |
1001 | 0 | glyphs = pte->text.data.glyphs; |
1002 | 0 | size = pte->text.size - pte->index; |
1003 | 0 | } else if (operation & TEXT_FROM_SINGLE_GLYPH) { |
1004 | 0 | glyphs = &pte->text.data.d_glyph; |
1005 | 0 | size = 1; |
1006 | 0 | } else if (operation & TEXT_FROM_STRING) { |
1007 | 0 | glyphs = &pte->outer_CID; |
1008 | 0 | size = 1; |
1009 | 0 | } else |
1010 | 0 | return_error(gs_error_rangecheck); |
1011 | | |
1012 | | /* |
1013 | | * PDF doesn't support glyphshow directly: we need to create a Type 0 |
1014 | | * font with an Identity CMap. Make sure all the glyph numbers fit |
1015 | | * into 16 bits. (Eventually we should support wider glyphs too, |
1016 | | * but this would require a different CMap.) |
1017 | | */ |
1018 | 0 | if (bsize < size * 2) |
1019 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1020 | 0 | { |
1021 | 0 | int i; |
1022 | 0 | byte *pchars = vbuf; |
1023 | |
|
1024 | 0 | for (i = 0; i < size; ++i) { |
1025 | 0 | ulong gnum = glyphs[i] - GS_MIN_CID_GLYPH; |
1026 | |
|
1027 | 0 | if (gnum & ~0xffffL) |
1028 | 0 | return_error(gs_error_rangecheck); |
1029 | 0 | *pchars++ = (byte)(gnum >> 8); |
1030 | 0 | *pchars++ = (byte)gnum; |
1031 | 0 | } |
1032 | 0 | } |
1033 | | |
1034 | | /* Find the original (unscaled) version of this font. */ |
1035 | | |
1036 | 0 | for (font = scaled_font; font->base != font; ) |
1037 | 0 | font = font->base; |
1038 | | /* Compute the scaling matrix. */ |
1039 | 0 | code = gs_matrix_invert(&font->FontMatrix, &scale_matrix); |
1040 | 0 | if (code < 0) |
1041 | 0 | return code; |
1042 | 0 | gs_matrix_multiply(&scale_matrix, &scaled_font->FontMatrix, &scale_matrix); |
1043 | | |
1044 | | /* Find or create the CIDFont resource. */ |
1045 | |
|
1046 | 0 | code = pdf_obtain_font_resource(penum, NULL, &pdsubf); |
1047 | 0 | if (code < 0) |
1048 | 0 | return code; |
1049 | | |
1050 | | /* Create the CMap and Type 0 font if they don't exist already. */ |
1051 | | |
1052 | 0 | if (pdsubf->u.cidfont.glyphshow_font_id != 0) |
1053 | 0 | font0 = (gs_font_type0 *)gs_find_font_by_id(font->dir, |
1054 | 0 | pdsubf->u.cidfont.glyphshow_font_id, &scaled_font->FontMatrix); |
1055 | 0 | if (font0 == NULL) { |
1056 | 0 | code = gs_font_type0_from_cidfont(&font0, font, font->WMode, |
1057 | 0 | &scale_matrix, font->memory); |
1058 | 0 | if (code < 0) |
1059 | 0 | return code; |
1060 | 0 | pdsubf->u.cidfont.glyphshow_font_id = font0->id; |
1061 | 0 | } |
1062 | | |
1063 | | /* Now handle the glyphshow as a show in the Type 0 font. */ |
1064 | | |
1065 | 0 | save = *pte; |
1066 | 0 | pte->current_font = pte->orig_font = (gs_font *)font0; |
1067 | | /* Patch the operation temporarily for init_fstack. */ |
1068 | 0 | pte->text.operation = (operation & ~TEXT_FROM_ANY) | TEXT_FROM_BYTES; |
1069 | | /* Patch the data for process_cmap_text. */ |
1070 | 0 | pte->text.data.bytes = vbuf; |
1071 | 0 | pte->text.size = size * 2; |
1072 | 0 | pte->index = 0; |
1073 | 0 | gs_type0_init_fstack(pte, pte->current_font); |
1074 | 0 | code = process_cmap_text(pte, vbuf, bsize); |
1075 | 0 | pte->current_font = scaled_font; |
1076 | 0 | pte->orig_font = save.orig_font; |
1077 | 0 | pte->text = save.text; |
1078 | 0 | pte->index = save.index + pte->index / 2; |
1079 | 0 | pte->fstack = save.fstack; |
1080 | 0 | return code; |
1081 | 0 | } |