2 |
- |
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
|
|
|
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 |
|
|
|
208 |
};
|
|
|
209 |
|
|
|
210 |
private int
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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 |
}
|