/src/libspectre/ghostscript/devices/vector/gdevpdti.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2020 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., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Bitmap font implementation for pdfwrite */ |
18 | | #include "memory_.h" |
19 | | #include "gx.h" |
20 | | #include "gxpath.h" |
21 | | #include "gserrors.h" |
22 | | #include "gsutil.h" |
23 | | #include "gdevpdfx.h" |
24 | | #include "gdevpdfg.h" |
25 | | #include "gdevpdtf.h" |
26 | | #include "gdevpdti.h" |
27 | | #include "gdevpdts.h" |
28 | | #include "gdevpdtw.h" |
29 | | #include "gdevpdtt.h" |
30 | | #include "gdevpdfo.h" |
31 | | #include "gxchar.h" /* For gs_show_enum */ |
32 | | |
33 | | /* ---------------- Private ---------------- */ |
34 | | |
35 | | /* Define the structure for a CharProc pseudo-resource. */ |
36 | | /*typedef struct pdf_char_proc_s pdf_char_proc_t;*/ /* gdevpdfx.h */ |
37 | | struct pdf_char_proc_s { |
38 | | pdf_resource_common(pdf_char_proc_t); |
39 | | pdf_char_proc_ownership_t *owner_fonts; /* fonts using this charproc. */ |
40 | | int y_offset; /* of character (0,0) */ |
41 | | int x_offset; /* of character (0,0) */ |
42 | | gs_point real_width; /* Not used with synthesised bitmap fonts. */ |
43 | | gs_point v; /* Not used with synthesised bitmap fonts. */ |
44 | | }; |
45 | | |
46 | | /* The descriptor is public for pdf_resource_type_structs. */ |
47 | | gs_public_st_suffix_add1(st_pdf_char_proc, pdf_char_proc_t, |
48 | | "pdf_char_proc_t", pdf_char_proc_enum_ptrs, pdf_char_proc_reloc_ptrs, |
49 | | st_pdf_resource, owner_fonts); |
50 | | |
51 | | struct pdf_char_proc_ownership_s { |
52 | | pdf_char_proc_t *char_proc; |
53 | | pdf_char_proc_ownership_t *font_next; /* next char_proc for same font */ |
54 | | pdf_char_proc_ownership_t *char_next; /* next char_proc for same charproc */ |
55 | | pdf_font_resource_t *font; |
56 | | gs_char char_code; /* Character code in PDF font. */ |
57 | | gs_glyph glyph; /* Glyph id in Postscript font. */ |
58 | | gs_string char_name; |
59 | | bool duplicate_char_name; |
60 | | }; |
61 | | gs_private_st_strings1_ptrs4(st_pdf_char_proc_ownership, pdf_char_proc_ownership_t, |
62 | | "pdf_char_proc_ownership_t", pdf_char_proc_ownership_enum_ptrs, |
63 | | pdf_char_proc_ownership_reloc_ptrs, char_name, char_proc, char_next, font_next, font); |
64 | | |
65 | | gs_private_st_ptrs1(st_pdf_bitmap_fonts, pdf_bitmap_fonts_t, |
66 | | "pdf_bitmap_fonts_t", pdf_bitmap_fonts_enum_ptrs, |
67 | | pdf_bitmap_fonts_reloc_ptrs, open_font); |
68 | | |
69 | | static inline long |
70 | | pdf_char_proc_id(const pdf_char_proc_t *pcp) |
71 | 0 | { |
72 | 0 | return pdf_resource_id((const pdf_resource_t *)pcp); |
73 | 0 | } |
74 | | |
75 | | /* Assign a code for a char_proc. */ |
76 | | static int |
77 | | assign_char_code(gx_device_pdf * pdev, gs_text_enum_t *pte) |
78 | 0 | { |
79 | 0 | pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts; |
80 | 0 | pdf_font_resource_t *pdfont = pbfs->open_font; /* Type 3 */ |
81 | 0 | int i, c = 0, code; |
82 | 0 | uint operation = pte->text.operation; |
83 | |
|
84 | 0 | if (pbfs->bitmap_encoding_id == 0) |
85 | 0 | pbfs->bitmap_encoding_id = pdf_obj_ref(pdev); |
86 | 0 | if (pdfont == 0 || pdfont->u.simple.LastChar == 255 || |
87 | 0 | !pbfs->use_open_font |
88 | 0 | ) { |
89 | | /* Start a new synthesized font. */ |
90 | 0 | char *pc; |
91 | |
|
92 | 0 | code = pdf_font_type3_alloc(pdev, &pdfont, pdf_write_contents_bitmap); |
93 | 0 | if (code < 0) |
94 | 0 | return code; |
95 | 0 | pdfont->u.simple.s.type3.bitmap_font = true; |
96 | 0 | if (pbfs->open_font == 0) |
97 | 0 | pdfont->rname[0] = 0; |
98 | 0 | else |
99 | 0 | strcpy(pdfont->rname, pbfs->open_font->rname); |
100 | 0 | pdfont->u.simple.s.type3.FontBBox.p.x = 0; |
101 | 0 | pdfont->u.simple.s.type3.FontBBox.p.y = 0; |
102 | 0 | pdfont->u.simple.s.type3.FontBBox.q.x = 0; |
103 | 0 | pdfont->u.simple.s.type3.FontBBox.q.y = 0; |
104 | 0 | pdfont->mark_glyph = NULL; |
105 | 0 | gs_make_identity(&pdfont->u.simple.s.type3.FontMatrix); |
106 | | /* |
107 | | * We "increment" the font name as a radix-26 "number". |
108 | | * This cannot possibly overflow. |
109 | | */ |
110 | 0 | for (pc = pdfont->rname; *pc == 'Z'; ++pc) |
111 | 0 | *pc = '@'; |
112 | 0 | if ((*pc)++ == 0) |
113 | 0 | *pc = 'A', pc[1] = 0; |
114 | 0 | pbfs->open_font = pdfont; |
115 | 0 | pbfs->use_open_font = true; |
116 | 0 | pdfont->u.simple.FirstChar = 255; |
117 | 0 | } |
118 | 0 | if ((operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) || |
119 | 0 | (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR))) { |
120 | 0 | unsigned char p = *pte->text.data.bytes; |
121 | 0 | unsigned char index = p / 8, bit = 0x01 << (p % 8); |
122 | |
|
123 | 0 | if (pdfont->used[index] & bit) { |
124 | 0 | for (i = 0;i < 256;i++) { |
125 | 0 | index = i / 8; |
126 | 0 | bit = 0x01 << (i % 8); |
127 | 0 | if (!(pdfont->used[index] & bit)) { |
128 | 0 | c = i; |
129 | 0 | break; |
130 | 0 | } |
131 | 0 | } |
132 | 0 | } else |
133 | 0 | c = p; |
134 | 0 | pdfont->used[index] |= bit; |
135 | 0 | if (c > pdfont->u.simple.LastChar) |
136 | 0 | pdfont->u.simple.LastChar = c; |
137 | |
|
138 | 0 | } else { |
139 | 0 | unsigned char index, bit; |
140 | 0 | c = ++(pdfont->u.simple.LastChar); |
141 | 0 | index = c / 8; |
142 | 0 | bit = 0x01 << (c % 8); |
143 | 0 | pdfont->used[index] |= bit; |
144 | 0 | } |
145 | 0 | if (c < pdfont->u.simple.FirstChar) |
146 | 0 | pdfont->u.simple.FirstChar = c; |
147 | |
|
148 | 0 | pdfont->Widths[c] = psdf_round(pdev->char_width.x, 100, 10); /* See |
149 | | pdf_write_Widths about rounding. We need to provide |
150 | | a compatible data for Tj. */ |
151 | 0 | if (c > pbfs->max_embedded_code) |
152 | 0 | pbfs->max_embedded_code = c; |
153 | |
|
154 | 0 | return c; |
155 | 0 | } |
156 | | |
157 | | /* Write the contents of a Type 3 bitmap or vector font resource. */ |
158 | | int |
159 | | pdf_write_contents_bitmap(gx_device_pdf *pdev, pdf_font_resource_t *pdfont) |
160 | 0 | { |
161 | 0 | stream *s = pdev->strm; |
162 | 0 | const pdf_char_proc_ownership_t *pcpo; |
163 | 0 | long diff_id = 0; |
164 | 0 | int code; |
165 | |
|
166 | 0 | if (pdfont->u.simple.s.type3.bitmap_font) |
167 | 0 | diff_id = pdev->text->bitmap_fonts->bitmap_encoding_id; |
168 | 0 | else { |
169 | | /* See comment in pdf_write_encoding. */ |
170 | 0 | diff_id = pdf_obj_ref(pdev); |
171 | 0 | } |
172 | 0 | code = pdf_write_encoding_ref(pdev, pdfont, diff_id); |
173 | 0 | if (code < 0) |
174 | 0 | return code; |
175 | 0 | stream_puts(s, "/CharProcs <<"); |
176 | | /* Write real characters. */ |
177 | 0 | for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo; |
178 | 0 | pcpo = pcpo->char_next |
179 | 0 | ) { |
180 | 0 | if (pdfont->u.simple.s.type3.bitmap_font) |
181 | 0 | pprintld2(s, "/a%ld %ld 0 R\n", (long)pcpo->char_code, |
182 | 0 | pdf_char_proc_id(pcpo->char_proc)); |
183 | 0 | else if (!pcpo-> duplicate_char_name) { |
184 | 0 | pdf_put_name(pdev, pcpo->char_name.data, pcpo->char_name.size); |
185 | 0 | pprintld1(s, " %ld 0 R\n", pdf_char_proc_id(pcpo->char_proc)); |
186 | 0 | } |
187 | 0 | pdf_record_usage_by_parent(pdev, pdf_char_proc_id(pcpo->char_proc), pdfont->object->id); |
188 | 0 | } |
189 | 0 | stream_puts(s, ">>"); |
190 | 0 | pprintg6(s, "/FontMatrix[%g %g %g %g %g %g]", |
191 | 0 | (float)pdfont->u.simple.s.type3.FontMatrix.xx, |
192 | 0 | (float)pdfont->u.simple.s.type3.FontMatrix.xy, |
193 | 0 | (float)pdfont->u.simple.s.type3.FontMatrix.yx, |
194 | 0 | (float)pdfont->u.simple.s.type3.FontMatrix.yy, |
195 | 0 | (float)pdfont->u.simple.s.type3.FontMatrix.tx, |
196 | 0 | (float)pdfont->u.simple.s.type3.FontMatrix.ty); |
197 | 0 | code = pdf_finish_write_contents_type3(pdev, pdfont); |
198 | 0 | if (code < 0) |
199 | 0 | return code; |
200 | 0 | if (!pdfont->u.simple.s.type3.bitmap_font && diff_id > 0) { |
201 | 0 | code = pdf_write_encoding(pdev, pdfont, diff_id, 0); |
202 | 0 | if (code < 0) |
203 | 0 | return code; |
204 | 0 | } |
205 | 0 | return 0; |
206 | 0 | } |
207 | | |
208 | | /* ---------------- Public ---------------- */ |
209 | | |
210 | | /* |
211 | | * Allocate and initialize bookkeeping for bitmap fonts. |
212 | | */ |
213 | | pdf_bitmap_fonts_t * |
214 | | pdf_bitmap_fonts_alloc(gs_memory_t *mem) |
215 | 0 | { |
216 | 0 | pdf_bitmap_fonts_t *pbfs = |
217 | 0 | gs_alloc_struct(mem, pdf_bitmap_fonts_t, &st_pdf_bitmap_fonts, |
218 | 0 | "pdf_bitmap_fonts_alloc"); |
219 | |
|
220 | 0 | if (pbfs == 0) |
221 | 0 | return 0; |
222 | 0 | memset(pbfs, 0, sizeof(*pbfs)); |
223 | 0 | pbfs->max_embedded_code = -1; |
224 | 0 | return pbfs; |
225 | 0 | } |
226 | | |
227 | | /* |
228 | | * Update text state at the end of a page. |
229 | | */ |
230 | | void |
231 | | pdf_close_text_page(gx_device_pdf *pdev) |
232 | 0 | { |
233 | | /* |
234 | | * When Acrobat Reader 3 prints a file containing a Type 3 font with a |
235 | | * non-standard Encoding, it apparently only emits the subset of the |
236 | | * font actually used on the page. Thus, if the "Download Fonts Once" |
237 | | * option is selected, characters not used on the page where the font |
238 | | * first appears will not be defined, and hence will print as blank if |
239 | | * used on subsequent pages. Thus, we can't allow a Type 3 font to |
240 | | * add additional characters on subsequent pages. |
241 | | */ |
242 | 0 | if (pdev->CompatibilityLevel <= 1.2) |
243 | 0 | pdev->text->bitmap_fonts->use_open_font = false; |
244 | 0 | } |
245 | | |
246 | | int |
247 | | pdf_charproc_y_offset(pdf_char_proc_t *pcp) |
248 | 0 | { |
249 | 0 | return pcp->y_offset; |
250 | 0 | } |
251 | | |
252 | | int |
253 | | pdf_charproc_x_offset(pdf_char_proc_t *pcp) |
254 | 0 | { |
255 | 0 | return pcp->x_offset; |
256 | 0 | } |
257 | | |
258 | | /* Attach a CharProc to a font. */ |
259 | | static int |
260 | | pdf_attach_charproc(gx_device_pdf * pdev, pdf_font_resource_t *pdfont, pdf_char_proc_t *pcp, |
261 | | gs_glyph glyph, gs_char char_code, const gs_const_string *gnstr) |
262 | 0 | { |
263 | 0 | pdf_char_proc_ownership_t *pcpo; |
264 | 0 | bool duplicate_char_name = false; |
265 | |
|
266 | 0 | for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) { |
267 | 0 | if (pcpo->glyph == glyph && pcpo->char_code == char_code) |
268 | 0 | return 0; |
269 | 0 | } |
270 | 0 | if (!pdfont->u.simple.s.type3.bitmap_font) { |
271 | 0 | for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) { |
272 | 0 | if (!bytes_compare(pcpo->char_name.data, pcpo->char_name.size, gnstr->data, gnstr->size)) { |
273 | 0 | duplicate_char_name = true; |
274 | 0 | break; |
275 | 0 | } |
276 | 0 | } |
277 | 0 | } |
278 | 0 | pcpo = gs_alloc_struct(pdev->pdf_memory, |
279 | 0 | pdf_char_proc_ownership_t, &st_pdf_char_proc_ownership, "pdf_attach_charproc"); |
280 | |
|
281 | 0 | if (pcpo == NULL) |
282 | 0 | return_error(gs_error_VMerror); |
283 | 0 | pcpo->font = pdfont; |
284 | 0 | pcpo->char_next = pdfont->u.simple.s.type3.char_procs; |
285 | 0 | pdfont->u.simple.s.type3.char_procs = pcpo; |
286 | 0 | pcpo->char_proc = pcp; |
287 | 0 | pcpo->font_next = pcp->owner_fonts; |
288 | 0 | pcp->owner_fonts = pcpo; |
289 | 0 | pcpo->char_code = char_code; |
290 | 0 | pcpo->glyph = glyph; |
291 | 0 | if (gnstr == NULL) { |
292 | 0 | pcpo->char_name.data = 0; |
293 | 0 | pcpo->char_name.size = 0; |
294 | 0 | } else { |
295 | 0 | pcpo->char_name.data = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, gnstr->size, "storage for charproc name"); |
296 | 0 | memcpy(pcpo->char_name.data, gnstr->data, gnstr->size); |
297 | 0 | pcpo->char_name.size = gnstr->size; |
298 | | // pcpo->char_name = *gnstr; |
299 | 0 | } |
300 | 0 | pcpo->duplicate_char_name = duplicate_char_name; |
301 | 0 | return 0; |
302 | 0 | } |
303 | | |
304 | | int |
305 | | pdf_free_charproc_ownership(gx_device_pdf * pdev, pdf_resource_t *pres) |
306 | 0 | { |
307 | 0 | pdf_char_proc_ownership_t *next, *pcpo = (pdf_char_proc_ownership_t *)pres; |
308 | |
|
309 | 0 | while (pcpo) { |
310 | 0 | next = pcpo->char_next; |
311 | 0 | if(pcpo->char_name.size != 0 && pcpo->char_name.data) { |
312 | 0 | gs_free_object(pdev->pdf_memory->non_gc_memory, pcpo->char_name.data, "free storage for charproc naem"); |
313 | | /* This causes PCL some trouble, don't know why yet FIXME-MEMORY |
314 | | gs_free_string(pdev->pdf_memory, (byte *)pcpo->char_name.data, pcpo->char_name.size, "Free CharProc name");*/ |
315 | 0 | pcpo->char_name.data = (byte *)0L; |
316 | 0 | pcpo->char_name.size = 0; |
317 | 0 | } |
318 | 0 | gs_free_object(pdev->pdf_memory, pcpo, "Free CharProc"); |
319 | 0 | pcpo = next; |
320 | 0 | } |
321 | 0 | return 0; |
322 | 0 | } |
323 | | |
324 | | /* Begin a CharProc for a synthesized (bitmap) font. */ |
325 | | int |
326 | | pdf_begin_char_proc(gx_device_pdf * pdev, int w, int h, int x_width, |
327 | | int y_offset, int x_offset, gs_id id, pdf_char_proc_t ** ppcp, |
328 | | pdf_stream_position_t * ppos) |
329 | 0 | { |
330 | 0 | gs_char char_code = 0; |
331 | 0 | pdf_bitmap_fonts_t *const pbfs = pdev->text->bitmap_fonts; |
332 | 0 | pdf_font_resource_t *font; |
333 | 0 | pdf_resource_t *pres; |
334 | 0 | pdf_char_proc_t *pcp; |
335 | 0 | int code; |
336 | | /* This code added to store PCL bitmap glyphs in type 3 fonts where possible */ |
337 | 0 | gs_glyph glyph = GS_NO_GLYPH; |
338 | 0 | gs_const_string *str = NULL; |
339 | 0 | gs_show_enum *show_enum = (gs_show_enum *)pdev->pte; |
340 | 0 | pdf_encoding_element_t *pet = 0; |
341 | | /* Since this is for text searching, its only useful if the character code |
342 | | * lies in an ASCII range, so we only handle some kinds of text layout. |
343 | | */ |
344 | 0 | int allowed_op = (show_enum->text.operation & |
345 | 0 | (TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR)); |
346 | | |
347 | | /* Check to see the current font is a type 3. We can get here if pdfwrite decides |
348 | | * it can't handle a font type, and renders to a bitmap instead. If that's the |
349 | | * case then we can't add the bitmap to the existing font (its not a type 3 font) |
350 | | * and must fall back to holding it in our fallback type 3 font 'collection'. |
351 | | */ |
352 | | /* Because the bitmaps are stored directly in the cache they already have any |
353 | | * effects caused by non-identity FontMatrix entries applied. So if the type 3 |
354 | | * font we created has a non-identity FontMatrix we can't use it and must |
355 | | * go back to collecting the bitmap into our fallback font. |
356 | | */ |
357 | 0 | if ((show_enum->current_font->FontType == ft_user_defined || |
358 | 0 | show_enum->current_font->FontType == ft_PDF_user_defined || |
359 | 0 | show_enum->current_font->FontType == ft_PCL_user_defined || |
360 | 0 | show_enum->current_font->FontType == ft_MicroType || |
361 | 0 | show_enum->current_font->FontType == ft_GL2_stick_user_defined || |
362 | 0 | show_enum->current_font->FontType == ft_GL2_531) && allowed_op && |
363 | 0 | show_enum->current_font->FontMatrix.xx == 1 && show_enum->current_font->FontMatrix.xy == 0 && |
364 | 0 | show_enum->current_font->FontMatrix.yx == 0 && show_enum->current_font->FontMatrix.yy == 1) { |
365 | 0 | pdf_char_proc_ownership_t *pcpo; |
366 | |
|
367 | 0 | gs_font_base *base = (gs_font_base *)show_enum->current_font; |
368 | 0 | code = pdf_attached_font_resource(pdev, show_enum->current_font, &font, NULL, NULL, NULL, NULL); |
369 | 0 | if (code < 0) |
370 | 0 | return code; |
371 | 0 | if (font == NULL) |
372 | 0 | return_error(gs_error_invalidfont); |
373 | | |
374 | | /* The text processing will have run past the glyph, so we need to 'back up' |
375 | | * by one and get it again in order to get the character code and glyph, and update |
376 | | * the pointer correctly. |
377 | | */ |
378 | 0 | show_enum->index--; |
379 | 0 | code = gs_default_next_char_glyph((gs_text_enum_t *)show_enum, (gs_char *)&char_code, &glyph); |
380 | 0 | if (code < 0) |
381 | 0 | return code; |
382 | | |
383 | | /* If the returned character code is outside the possible Encoding for |
384 | | * a type 3 font, then set pet to NULL, this means we will fall back to |
385 | | * the 'collection' font, as pet is checked below. |
386 | | */ |
387 | 0 | if ((int)char_code >= 0 && (int)char_code <= 255) { |
388 | 0 | pet = &font->u.simple.Encoding[char_code]; |
389 | 0 | if (pet) { |
390 | | /* Check to see if we *already* have this glyph in this font. If |
391 | | * we do then we can't add it to this font. Setting pet to 0 |
392 | | * falls back to the collection method. |
393 | | */ |
394 | 0 | for (pcpo = font->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) { |
395 | 0 | if (pcpo->glyph == pet->glyph && pcpo->char_code == char_code) { |
396 | 0 | pet = 0x00; |
397 | 0 | break; |
398 | 0 | } |
399 | 0 | } |
400 | 0 | } |
401 | 0 | } |
402 | 0 | else |
403 | 0 | pet = 0x00; |
404 | | |
405 | | /* We need a glyph name for the type 3 font's Encoding, if we haven't got one |
406 | | * then we need to give up, something about the font or text is not acceptable |
407 | | * (see various comments above). |
408 | | */ |
409 | 0 | if (pet && pet->glyph != GS_NO_GLYPH && !(pet->str.size == 7 && |
410 | 0 | !strncmp((const char *)pet->str.data, ".notdef", 7))) { |
411 | 0 | if (char_code < font->u.simple.FirstChar) |
412 | 0 | font->u.simple.FirstChar = char_code; |
413 | 0 | if ((int)char_code > font->u.simple.LastChar) |
414 | 0 | font->u.simple.LastChar = char_code; |
415 | 0 | base->FontBBox.q.x = max(base->FontBBox.q.x, w); |
416 | 0 | base->FontBBox.q.y = max(base->FontBBox.q.y, y_offset + h); |
417 | 0 | str = &pet->str; |
418 | 0 | glyph = pet->glyph; |
419 | | /* This is to work around a weird Acrobat bug. If the Encoding of a type 3 |
420 | | * (possibly other types) is simply a standard encoding (eg WinAnsiEncoding) |
421 | | * then Acrobat 4 & 8 just ignore the glyphs altogether. This forces us to write |
422 | | * all the used glyphs as /Differencess, and that makes it work <sigh> |
423 | | */ |
424 | 0 | pet->is_difference = 1; |
425 | 0 | font->Widths[char_code] = psdf_round(pdev->char_width.x, 100, 10); /* See |
426 | | pdf_write_Widths about rounding. We need to provide |
427 | | a compatible data for Tj. */ |
428 | 0 | } else { |
429 | 0 | char_code = assign_char_code(pdev, pdev->pte); |
430 | 0 | font = pbfs->open_font; /* Type 3 */ |
431 | 0 | } |
432 | 0 | } else { |
433 | 0 | char_code = assign_char_code(pdev, pdev->pte); |
434 | 0 | font = pbfs->open_font; /* Type 3 */ |
435 | 0 | } |
436 | | |
437 | 0 | code = pdf_begin_resource(pdev, resourceCharProc, id, &pres); |
438 | 0 | if (code < 0) |
439 | 0 | return code; |
440 | 0 | pcp = (pdf_char_proc_t *) pres; |
441 | 0 | code = pdf_attach_charproc(pdev, font, pcp, glyph, char_code, str); |
442 | 0 | if (code < 0) |
443 | 0 | return code; |
444 | 0 | pres->object->written = true; |
445 | 0 | { |
446 | 0 | stream *s = pdev->strm; |
447 | | |
448 | | /* |
449 | | * The resource file is positionable, so rather than use an |
450 | | * object reference for the length, we'll go back and fill it in |
451 | | * at the end of the definition. Take 1M as the longest |
452 | | * definition we can handle. (This used to be 10K, but there was |
453 | | * a real file that exceeded this limit.) |
454 | | */ |
455 | 0 | stream_puts(s, "<</Length >>stream\n"); |
456 | 0 | ppos->start_pos = stell(s); |
457 | 0 | } |
458 | 0 | code = pdf_begin_encrypt(pdev, &pdev->strm, pres->object->id); |
459 | 0 | if (code < 0) |
460 | 0 | return code; |
461 | 0 | pcp->y_offset = y_offset; |
462 | 0 | pcp->x_offset = x_offset; |
463 | 0 | font->u.simple.s.type3.FontBBox.q.x = |
464 | 0 | max(font->u.simple.s.type3.FontBBox.q.x, w); |
465 | 0 | font->u.simple.s.type3.FontBBox.q.y = |
466 | 0 | max(font->u.simple.s.type3.FontBBox.q.y, y_offset + h); |
467 | 0 | font->u.simple.s.type3.max_y_offset = |
468 | 0 | max(font->u.simple.s.type3.max_y_offset, h + (h >> 2)); |
469 | 0 | pcp->real_width.x = w; |
470 | 0 | pcp->real_width.y = y_offset + h; |
471 | 0 | *ppcp = pcp; |
472 | 0 | return 0; |
473 | 0 | } |
474 | | |
475 | | /* End a CharProc. */ |
476 | | int |
477 | | pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos) |
478 | 0 | { |
479 | 0 | stream *s; |
480 | 0 | gs_offset_t start_pos, end_pos, length; |
481 | |
|
482 | 0 | if (pdf_end_encrypt(pdev)) |
483 | 0 | s_close_filters(&pdev->strm, pdev->strm->strm); |
484 | |
|
485 | 0 | s = pdev->strm; |
486 | 0 | start_pos = ppos->start_pos; |
487 | 0 | end_pos = stell(s); |
488 | 0 | length = end_pos - start_pos; |
489 | 0 | if (length > 999999) |
490 | 0 | return_error(gs_error_limitcheck); |
491 | 0 | sseek(s, start_pos - 15); |
492 | 0 | pprintd1(s, "%d", length); |
493 | 0 | sseek(s, end_pos); |
494 | 0 | if (pdev->PDFA != 0) |
495 | 0 | stream_puts(s, "\n"); |
496 | 0 | stream_puts(s, "endstream\n"); |
497 | 0 | pdf_end_separate(pdev, resourceCharProc); |
498 | 0 | return 0; |
499 | 0 | } |
500 | | |
501 | | /* Mark glyph names for garbager. */ |
502 | | void |
503 | | pdf_mark_glyph_names(const pdf_font_resource_t *pdfont, const gs_memory_t *memory) |
504 | 0 | { |
505 | 0 | if (pdfont->mark_glyph == NULL) { |
506 | | /* Synthesised bitmap fonts pass here. */ |
507 | 0 | return; |
508 | 0 | } |
509 | 0 | if (pdfont->u.simple.Encoding != NULL) { |
510 | 0 | int i; |
511 | |
|
512 | 0 | for (i = 0; i < 256; i++) |
513 | 0 | if (pdfont->u.simple.Encoding[i].glyph != GS_NO_GLYPH) |
514 | 0 | pdfont->mark_glyph(memory, pdfont->u.simple.Encoding[i].glyph, pdfont->mark_glyph_data); |
515 | 0 | } |
516 | 0 | if (pdfont->FontType == ft_user_defined || |
517 | 0 | pdfont->FontType == ft_PDF_user_defined || |
518 | 0 | pdfont->FontType == ft_PCL_user_defined || |
519 | 0 | pdfont->FontType == ft_MicroType || |
520 | 0 | pdfont->FontType == ft_GL2_stick_user_defined || |
521 | 0 | pdfont->FontType == ft_GL2_531) { |
522 | 0 | const pdf_char_proc_ownership_t *pcpo = pdfont->u.simple.s.type3.char_procs; |
523 | |
|
524 | 0 | for (; pcpo != NULL; pcpo = pcpo->font_next) |
525 | 0 | pdfont->mark_glyph(memory, pcpo->glyph, pdfont->mark_glyph_data); |
526 | 0 | } |
527 | 0 | } |
528 | | |
529 | | /* Put out a reference to an image as a character in a synthesized font. */ |
530 | | int |
531 | | pdf_do_char_image(gx_device_pdf * pdev, const pdf_char_proc_t * pcp, |
532 | | const gs_matrix * pimat) |
533 | 0 | { |
534 | | /* We need to choose a font, which use the charproc. |
535 | | In most cases it is the last font, which the charproc is attached to. |
536 | | If the charproc is substituted, it causes a font change. */ |
537 | 0 | const pdf_char_proc_ownership_t * pcpo = pcp->owner_fonts; |
538 | 0 | pdf_font_resource_t *pdfont = pcpo->font; |
539 | 0 | byte ch = pcpo->char_code; |
540 | 0 | pdf_text_state_values_t values; |
541 | |
|
542 | 0 | values.character_spacing = 0; |
543 | 0 | values.pdfont = pdfont; |
544 | 0 | values.size = 1; |
545 | 0 | values.matrix = *pimat; |
546 | 0 | values.render_mode = pdev->pte->pgs->text_rendering_mode; |
547 | 0 | values.word_spacing = 0; |
548 | 0 | pdf_set_text_state_values(pdev, &values); |
549 | 0 | pdf_bitmap_char_update_bbox(pdev, pcp->x_offset, pcp->y_offset, pcp->real_width.x, pcp->real_width.y); |
550 | 0 | pdf_append_chars(pdev, &ch, 1, pdfont->Widths[ch] * pimat->xx, 0.0, false); |
551 | 0 | return 0; |
552 | 0 | } |
553 | | |
554 | | /* |
555 | | * Write the Encoding for bitmap fonts, if needed. |
556 | | */ |
557 | | int |
558 | | pdf_write_bitmap_fonts_Encoding(gx_device_pdf *pdev) |
559 | 0 | { |
560 | 0 | pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts; |
561 | |
|
562 | 0 | if (pbfs->bitmap_encoding_id) { |
563 | 0 | stream *s; |
564 | 0 | int i; |
565 | |
|
566 | 0 | pdf_open_separate(pdev, pbfs->bitmap_encoding_id, resourceEncoding); |
567 | 0 | s = pdev->strm; |
568 | | /* |
569 | | * Even though the PDF reference documentation says that a |
570 | | * BaseEncoding key is required unless the encoding is |
571 | | * "based on the base font's encoding" (and there is no base |
572 | | * font in this case), Acrobat 2.1 gives an error if the |
573 | | * BaseEncoding key is present. |
574 | | */ |
575 | 0 | stream_puts(s, "<</Type/Encoding/Differences[0"); |
576 | 0 | for (i = 0; i <= pbfs->max_embedded_code; ++i) { |
577 | 0 | if (!(i & 15)) |
578 | 0 | stream_puts(s, "\n"); |
579 | 0 | pprintd1(s, "/a%d", i); |
580 | 0 | } |
581 | 0 | stream_puts(s, "\n] >>\n"); |
582 | 0 | pdf_end_separate(pdev, resourceEncoding); |
583 | 0 | pbfs->bitmap_encoding_id = 0; |
584 | 0 | } |
585 | 0 | return 0; |
586 | 0 | } |
587 | | |
588 | | /* |
589 | | * Start charproc accumulation for a Type 3 font. |
590 | | */ |
591 | | int |
592 | | pdf_start_charproc_accum(gx_device_pdf *pdev) |
593 | 0 | { |
594 | 0 | pdf_char_proc_t *pcp; |
595 | 0 | pdf_resource_t *pres; |
596 | 0 | int id = gs_next_ids(pdev->memory, 1); |
597 | 0 | int code = pdf_enter_substream(pdev, resourceCharProc, id, |
598 | 0 | &pres, false, pdev->CompressFonts); |
599 | |
|
600 | 0 | if (code < 0) |
601 | 0 | return code; |
602 | 0 | pres->rid = id; |
603 | 0 | pcp = (pdf_char_proc_t *)pres; |
604 | 0 | pcp->owner_fonts = NULL; |
605 | 0 | return 0; |
606 | 0 | } |
607 | | |
608 | | /* |
609 | | * Install charproc accumulator for a Type 3 font. |
610 | | */ |
611 | | int |
612 | | pdf_set_charproc_attrs(gx_device_pdf *pdev, gs_font *font, double *pw, int narg, |
613 | | gs_text_cache_control_t control, gs_char ch, bool scale_100) |
614 | 0 | { |
615 | 0 | pdf_font_resource_t *pdfont; |
616 | 0 | pdf_resource_t *pres = pdev->accumulating_substream_resource; |
617 | 0 | pdf_char_proc_t *pcp; |
618 | 0 | int code; |
619 | |
|
620 | 0 | code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL); |
621 | 0 | if (code < 0) |
622 | 0 | return code; |
623 | 0 | pcp = (pdf_char_proc_t *)pres; |
624 | 0 | pcp->owner_fonts = NULL; |
625 | 0 | pcp->real_width.x = pw[font->WMode && narg > 6 ? 6 : 0]; |
626 | 0 | pcp->real_width.y = pw[font->WMode && narg > 6 ? 7 : 1]; |
627 | 0 | pcp->v.x = (narg > 8 ? pw[8] : 0); |
628 | 0 | pcp->v.y = (narg > 8 ? pw[9] : 0); |
629 | 0 | if (control == TEXT_SET_CHAR_WIDTH) { |
630 | | /* PLRM 5.7.1 "BuildGlyph" reads : "Normally, it is unnecessary and |
631 | | undesirable to initialize the current color parameter, because show |
632 | | is defined to paint glyphs with the current color." |
633 | | However comparefiles/Bug687044.ps doesn't follow that. */ |
634 | 0 | pdev->skip_colors = false; |
635 | 0 | pprintg1(pdev->strm, "%g 0 d0\n", (float)pw[0]); |
636 | | /* The colour change described above can't affect PCL fonts and we need |
637 | | * all glyphs to be noted as cached in order for the bitmap font cache |
638 | | * probing to work properly. |
639 | | */ |
640 | 0 | if (font->FontType == ft_PCL_user_defined || font->FontType == ft_GL2_stick_user_defined |
641 | 0 | || font->FontType == ft_GL2_531 || font->FontType == ft_MicroType) |
642 | 0 | pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7); |
643 | 0 | } else { |
644 | 0 | double d; |
645 | 0 | pdev->skip_colors = true; |
646 | 0 | if (pw[4] < pw[2]) { |
647 | 0 | d = pw[2]; |
648 | 0 | pw[2] = pw[4]; |
649 | 0 | pw[4] = d; |
650 | 0 | } |
651 | 0 | if (pw[5] < pw[3]) { |
652 | 0 | d = pw[5]; |
653 | 0 | pw[5] = pw[3]; |
654 | 0 | pw[3] = d; |
655 | 0 | } |
656 | 0 | pprintg6(pdev->strm, "%g %g %g %g %g %g d1\n", |
657 | 0 | (float)pw[0], (float)0.0, (float)pw[2], |
658 | 0 | (float)pw[3], (float)pw[4], (float)pw[5]); |
659 | 0 | pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7); |
660 | 0 | } |
661 | | /* See comments in pdf_text_process regarding type 3 CharProc accumulation |
662 | | * Initially this matrix was emitted there, at the start of the accumulator |
663 | | * but if we do that then GS incorrectly applied the matrix to the 'd1' |
664 | | * operator. We write the scale matrix here because this is *after* the |
665 | | * 'd1' has been emitted above, and so does not affect it. |
666 | | */ |
667 | 0 | if (scale_100) { |
668 | 0 | code = stream_puts(pdev->strm, "0.01 0 0 0.01 0 0 cm\n"); |
669 | 0 | if (code < 0) |
670 | 0 | return code; |
671 | 0 | } |
672 | 0 | return 0; |
673 | 0 | } |
674 | | |
675 | | /* |
676 | | * Open a stream object in the temporary file. |
677 | | */ |
678 | | |
679 | | int |
680 | | pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype, |
681 | | gs_id id, pdf_resource_t **ppres, bool reserve_object_id, int options) |
682 | 0 | { |
683 | 0 | int code; |
684 | 0 | pdf_resource_t *pres; |
685 | 0 | stream *s, *save_strm = pdev->strm; |
686 | 0 | pdf_data_writer_t writer; |
687 | 0 | static const pdf_filter_names_t fnames = { |
688 | 0 | PDF_FILTER_NAMES |
689 | 0 | }; |
690 | |
|
691 | 0 | pdev->streams.save_strm = pdev->strm; |
692 | |
|
693 | 0 | if (rtype >= NUM_RESOURCE_TYPES) |
694 | 0 | rtype = resourceOther; |
695 | 0 | code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id), |
696 | 0 | pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1); |
697 | 0 | if (code < 0) |
698 | 0 | return code; |
699 | 0 | cos_become(pres->object, cos_type_stream); |
700 | 0 | s = cos_write_stream_alloc((cos_stream_t *)pres->object, pdev, "pdf_enter_substream"); |
701 | 0 | if (s == 0) |
702 | 0 | return_error(gs_error_VMerror); |
703 | 0 | pdev->strm = s; |
704 | 0 | code = pdf_append_data_stream_filters(pdev, &writer, |
705 | 0 | options | DATA_STREAM_NOLENGTH, pres->object->id); |
706 | 0 | if (code < 0) { |
707 | 0 | pdev->strm = save_strm; |
708 | 0 | return code; |
709 | 0 | } |
710 | 0 | code = pdf_put_filters((cos_dict_t *)pres->object, pdev, writer.binary.strm, &fnames); |
711 | 0 | if (code < 0) { |
712 | 0 | pdev->strm = save_strm; |
713 | 0 | return code; |
714 | 0 | } |
715 | 0 | pdev->strm = writer.binary.strm; |
716 | 0 | *ppres = pres; |
717 | 0 | return 0; |
718 | 0 | } |
719 | | |
720 | | /* |
721 | | * Close a stream object in the temporary file. |
722 | | */ |
723 | | int |
724 | | pdf_close_aside(gx_device_pdf *pdev) |
725 | 0 | { |
726 | | /* We should call pdf_end_data here, but we don't want to put pdf_data_writer_t |
727 | | into pdf_substream_save stack to simplify garbager descriptors. |
728 | | Use a lower level functions instead that. */ |
729 | 0 | stream *s = pdev->strm; |
730 | 0 | cos_stream_t *pcs = cos_stream_from_pipeline(s); |
731 | 0 | int status = s_close_filters(&s, NULL); |
732 | |
|
733 | 0 | pdev->strm = pdev->streams.save_strm; |
734 | 0 | if (status < 0) |
735 | 0 | return(gs_note_error(gs_error_ioerror)); |
736 | | |
737 | 0 | if (!pcs) |
738 | 0 | return gs_note_error(gs_error_ioerror); |
739 | | |
740 | 0 | pcs->is_open = false; |
741 | 0 | return 0; |
742 | 0 | } |
743 | | |
744 | | /* |
745 | | * Enter the substream accumulation mode. |
746 | | */ |
747 | | int |
748 | | pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype, |
749 | | gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress) |
750 | 0 | { |
751 | 0 | int sbstack_ptr = pdev->sbstack_depth; |
752 | 0 | pdf_resource_t *pres; |
753 | 0 | stream *save_strm = pdev->strm; |
754 | 0 | int code; |
755 | |
|
756 | 0 | if (pdev->sbstack_depth >= pdev->sbstack_size) |
757 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
758 | 0 | if (pdev->sbstack[sbstack_ptr].text_state == 0) { |
759 | 0 | pdev->sbstack[sbstack_ptr].text_state = pdf_text_state_alloc(pdev->pdf_memory); |
760 | 0 | if (pdev->sbstack[sbstack_ptr].text_state == 0) |
761 | 0 | return_error(gs_error_VMerror); |
762 | 0 | } |
763 | 0 | code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id, |
764 | 0 | (compress ? DATA_STREAM_COMPRESS : 0)); |
765 | 0 | if (code < 0) |
766 | 0 | return code; |
767 | 0 | code = pdf_save_viewer_state(pdev, NULL); |
768 | 0 | if (code < 0) { |
769 | 0 | pdev->strm = save_strm; |
770 | 0 | return code; |
771 | 0 | } |
772 | 0 | pdev->sbstack[sbstack_ptr].context = pdev->context; |
773 | 0 | pdf_text_state_copy(pdev->sbstack[sbstack_ptr].text_state, pdev->text->text_state); |
774 | 0 | pdf_set_text_state_default(pdev->text->text_state); |
775 | 0 | pdev->sbstack[sbstack_ptr].clip_path = pdev->clip_path; |
776 | 0 | pdev->clip_path = 0; |
777 | 0 | pdev->sbstack[sbstack_ptr].clip_path_id = pdev->clip_path_id; |
778 | 0 | pdev->clip_path_id = pdev->no_clip_path_id; |
779 | 0 | pdev->sbstack[sbstack_ptr].vgstack_bottom = pdev->vgstack_bottom; |
780 | 0 | pdev->vgstack_bottom = pdev->vgstack_depth; |
781 | 0 | pdev->sbstack[sbstack_ptr].strm = save_strm; |
782 | 0 | pdev->sbstack[sbstack_ptr].procsets = pdev->procsets; |
783 | 0 | pdev->sbstack[sbstack_ptr].substream_Resources = pdev->substream_Resources; |
784 | 0 | pdev->sbstack[sbstack_ptr].skip_colors = pdev->skip_colors; |
785 | 0 | pdev->sbstack[sbstack_ptr].font3 = pdev->font3; |
786 | 0 | pdev->sbstack[sbstack_ptr].accumulating_substream_resource = pdev->accumulating_substream_resource; |
787 | 0 | pdev->sbstack[sbstack_ptr].charproc_just_accumulated = pdev->charproc_just_accumulated; |
788 | 0 | pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object; |
789 | 0 | pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict; |
790 | 0 | pdev->sbstack[sbstack_ptr].objname = pdev->objname; |
791 | 0 | pdev->sbstack[sbstack_ptr].last_charpath_op = pdev->last_charpath_op; |
792 | 0 | pdev->skip_colors = false; |
793 | 0 | pdev->charproc_just_accumulated = false; |
794 | 0 | pdev->pres_soft_mask_dict = NULL; |
795 | 0 | pdev->objname.data = NULL; |
796 | 0 | pdev->objname.size = 0; |
797 | | /* Do not reset pdev->accumulating_a_global_object - it inherits. */ |
798 | 0 | pdev->sbstack_depth++; |
799 | 0 | pdev->procsets = 0; |
800 | 0 | pdev->font3 = 0; |
801 | 0 | pdev->context = PDF_IN_STREAM; |
802 | 0 | pdev->accumulating_substream_resource = pres; |
803 | 0 | pdev->last_charpath_op = 0; |
804 | | /* Do not alter type3charpath, inherit the current value. We need to know if */ |
805 | | /* we are inside a charpath operation, and only reset this when the charpath */ |
806 | | /* is complete */ |
807 | 0 | if (rtype != resourceXObject) |
808 | 0 | pdf_reset_graphics(pdev); |
809 | 0 | else { |
810 | 0 | if (pdev->vg_initial_set) |
811 | 0 | pdev->state.blend_mode = pdev->vg_initial.blend_mode; |
812 | 0 | } |
813 | 0 | *ppres = pres; |
814 | 0 | return 0; |
815 | 0 | } |
816 | | |
817 | | /* |
818 | | * Exit the substream accumulation mode. |
819 | | */ |
820 | | int |
821 | | pdf_exit_substream(gx_device_pdf *pdev) |
822 | 0 | { |
823 | 0 | int code, code1; |
824 | 0 | int sbstack_ptr; |
825 | |
|
826 | 0 | if (pdev->sbstack_depth <= 0) |
827 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
828 | 0 | code = pdf_open_contents(pdev, PDF_IN_STREAM); |
829 | 0 | sbstack_ptr = pdev->sbstack_depth - 1; |
830 | 0 | while (pdev->vgstack_depth > pdev->vgstack_bottom) { |
831 | 0 | code1 = pdf_restore_viewer_state(pdev, pdev->strm); |
832 | 0 | if (code >= 0) |
833 | 0 | code = code1; |
834 | 0 | } |
835 | 0 | if (pdev->clip_path != 0) |
836 | 0 | gx_path_free(pdev->clip_path, "pdf_end_charproc_accum"); |
837 | 0 | code1 = pdf_close_aside(pdev); |
838 | 0 | if (code1 < 0 && code >= 0) |
839 | 0 | code = code1; |
840 | 0 | pdev->context = pdev->sbstack[sbstack_ptr].context; |
841 | 0 | pdf_text_state_copy(pdev->text->text_state, pdev->sbstack[sbstack_ptr].text_state); |
842 | 0 | gs_free_object(pdev->pdf_memory, pdev->sbstack[sbstack_ptr].text_state, "free text state for stream"); |
843 | 0 | pdev->sbstack[sbstack_ptr].text_state = 0; |
844 | 0 | pdev->clip_path = pdev->sbstack[sbstack_ptr].clip_path; |
845 | 0 | pdev->sbstack[sbstack_ptr].clip_path = 0; |
846 | 0 | pdev->clip_path_id = pdev->sbstack[sbstack_ptr].clip_path_id; |
847 | 0 | pdev->vgstack_bottom = pdev->sbstack[sbstack_ptr].vgstack_bottom; |
848 | 0 | pdev->strm = pdev->sbstack[sbstack_ptr].strm; |
849 | 0 | pdev->sbstack[sbstack_ptr].strm = 0; |
850 | 0 | pdev->procsets = pdev->sbstack[sbstack_ptr].procsets; |
851 | 0 | pdev->substream_Resources = pdev->sbstack[sbstack_ptr].substream_Resources; |
852 | 0 | pdev->sbstack[sbstack_ptr].substream_Resources = 0; |
853 | 0 | pdev->skip_colors = pdev->sbstack[sbstack_ptr].skip_colors; |
854 | 0 | pdev->font3 = pdev->sbstack[sbstack_ptr].font3; |
855 | 0 | pdev->sbstack[sbstack_ptr].font3 = 0; |
856 | 0 | pdev->accumulating_substream_resource = pdev->sbstack[sbstack_ptr].accumulating_substream_resource; |
857 | 0 | pdev->sbstack[sbstack_ptr].accumulating_substream_resource = 0; |
858 | 0 | pdev->charproc_just_accumulated = pdev->sbstack[sbstack_ptr].charproc_just_accumulated; |
859 | 0 | pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object; |
860 | 0 | pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict; |
861 | 0 | pdev->objname = pdev->sbstack[sbstack_ptr].objname; |
862 | 0 | pdev->last_charpath_op = pdev->sbstack[sbstack_ptr].last_charpath_op; |
863 | 0 | pdev->sbstack_depth = sbstack_ptr; |
864 | 0 | code1 = pdf_restore_viewer_state(pdev, NULL); |
865 | 0 | if (code1 < 0 && code >= 0) |
866 | 0 | code = code1; |
867 | 0 | return code; |
868 | 0 | } |
869 | | |
870 | | static bool |
871 | | pdf_is_same_charproc_attrs1(gx_device_pdf *pdev, pdf_char_proc_t *pcp0, pdf_char_proc_t *pcp1) |
872 | 0 | { |
873 | 0 | if (pcp0->real_width.x != pcp1->real_width.x) |
874 | 0 | return false; |
875 | 0 | if (pcp0->real_width.y != pcp1->real_width.y) |
876 | 0 | return false; |
877 | 0 | if (pcp0->v.x != pcp1->v.x) |
878 | 0 | return false; |
879 | 0 | if (pcp0->v.y != pcp1->v.y) |
880 | 0 | return false; |
881 | 0 | return true; |
882 | 0 | } |
883 | | |
884 | | typedef struct charproc_compatibility_data_s { |
885 | | const pdf_char_glyph_pairs_t *cgp; |
886 | | pdf_font_resource_t *pdfont; |
887 | | gs_char char_code; |
888 | | gs_glyph glyph; |
889 | | gs_font *font; |
890 | | } charproc_compatibility_data_t; |
891 | | |
892 | | static bool |
893 | | is_char_code_used(pdf_font_resource_t *pdfont, gs_char char_code) |
894 | 0 | { |
895 | 0 | pdf_char_proc_ownership_t *pcpo; |
896 | |
|
897 | 0 | for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) { |
898 | 0 | if (pcpo->char_code == char_code) { |
899 | 0 | return true; |
900 | 0 | } |
901 | 0 | } |
902 | 0 | return false; |
903 | 0 | } |
904 | | |
905 | | static int |
906 | | pdf_is_charproc_compatible(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1) |
907 | 0 | { |
908 | 0 | charproc_compatibility_data_t *data = (charproc_compatibility_data_t *)pdev->find_resource_param; |
909 | 0 | pdf_char_proc_t *pcp0 = (pdf_char_proc_t *)pres0; |
910 | 0 | pdf_char_proc_t *pcp1 = (pdf_char_proc_t *)pres1; |
911 | 0 | pdf_font_resource_t *pdfont = data->pdfont; |
912 | 0 | pdf_char_proc_ownership_t *pcpo; |
913 | 0 | pdf_font_cache_elem_t **e; |
914 | 0 | bool can_add_to_current_font = false, computed_can_add_to_current_font = false; |
915 | | |
916 | | /* Does it have same attributes ? */ |
917 | 0 | if (!pdf_is_same_charproc_attrs1(pdev, pcp0, pcp1)) |
918 | 0 | return 0; |
919 | | /* Is it from same font ? */ |
920 | 0 | for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) { |
921 | 0 | if (pdfont == pcpo->font) { |
922 | | /* Check for encoding conflict. */ |
923 | 0 | if (pcpo->char_code == data->char_code && pcpo->glyph == data->glyph) |
924 | 0 | return 1; /* Same char code. */ |
925 | 0 | if (!computed_can_add_to_current_font) { |
926 | 0 | can_add_to_current_font = !is_char_code_used(pdfont, data->char_code); |
927 | 0 | computed_can_add_to_current_font = true; |
928 | 0 | } |
929 | 0 | if (can_add_to_current_font) |
930 | 0 | return 1; /* No conflict. */ |
931 | 0 | } |
932 | 0 | } |
933 | | /* Look for another font with same encoding, |
934 | | because we want to reduce the number of new fonts. |
935 | | We also restrict with ones attached to same PS font, |
936 | | otherwise it creates too mixed fonts and disturbs word breaks. |
937 | | */ |
938 | 0 | e = pdf_locate_font_cache_elem(pdev, data->font); |
939 | 0 | if (e != NULL) { |
940 | 0 | for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) { |
941 | 0 | if (pcpo->char_code != data->char_code || pcpo->glyph != data->glyph) |
942 | 0 | continue; /* Need same Encoding to generate a proper ToUnicode. */ |
943 | 0 | if (pdfont->u.simple.s.type3.bitmap_font != pcpo->font->u.simple.s.type3.bitmap_font) |
944 | 0 | continue; |
945 | 0 | if (gs_matrix_compare(&pdfont->u.simple.s.type3.FontMatrix, &pcpo->font->u.simple.s.type3.FontMatrix)) |
946 | 0 | continue; |
947 | 0 | if (data->cgp != NULL) { |
948 | 0 | if (!pdf_check_encoding_compatibility(pcpo->font, data->cgp->s, data->cgp->num_all_chars)) |
949 | 0 | continue; |
950 | 0 | } |
951 | 0 | if ((*e)->pdfont != pcpo->font) |
952 | 0 | continue; |
953 | 0 | data->pdfont = pcpo->font; /* Switch to the other font. */ |
954 | 0 | return 1; |
955 | 0 | } |
956 | 0 | } |
957 | | /* Check whether it can be added into the current font. */ |
958 | 0 | if (!computed_can_add_to_current_font) |
959 | 0 | can_add_to_current_font = !is_char_code_used(pdfont, data->char_code); |
960 | 0 | if (!can_add_to_current_font) { |
961 | | /* Can't substitute due to encoding conflict. */ |
962 | 0 | return 0; |
963 | 0 | } |
964 | | /* The current font will share it with another font. */ |
965 | 0 | return 1; |
966 | 0 | } |
967 | | |
968 | | static int |
969 | | pdf_find_same_charproc_aux(gx_device_pdf *pdev, |
970 | | pdf_font_resource_t **ppdfont, pdf_char_proc_t **ppcp) |
971 | 0 | { |
972 | 0 | pdf_char_proc_ownership_t *pcpo; |
973 | 0 | int code; |
974 | | |
975 | | /* fixme: this passes parameters to pdf_is_charproc_compatible |
976 | | through special gx_device_pdf field pdev->find_resource_param |
977 | | due to prototype limitation of pdf_find_same_resource. |
978 | | It would be better to change the client data argument type in there to void. */ |
979 | 0 | for (pcpo = (*ppdfont)->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) { |
980 | 0 | pdf_char_proc_t *pcp = pcpo->char_proc; |
981 | |
|
982 | 0 | if (*ppcp != pcp && pdf_is_same_charproc_attrs1(pdev, *ppcp, pcp)) { |
983 | 0 | cos_object_t *pco0 = pcp->object; |
984 | 0 | cos_object_t *pco1 = (*ppcp)->object; |
985 | |
|
986 | 0 | code = pco0->cos_procs->equal(pco0, pco1, pdev); |
987 | 0 | if (code < 0) { |
988 | 0 | return code; |
989 | 0 | } |
990 | 0 | if (code) { |
991 | 0 | *ppcp = pcp; |
992 | 0 | return 1; |
993 | 0 | } |
994 | 0 | } |
995 | 0 | } |
996 | 0 | return pdf_find_same_resource(pdev, resourceCharProc, (pdf_resource_t **)ppcp, pdf_is_charproc_compatible); |
997 | 0 | } |
998 | | static int |
999 | | pdf_find_same_charproc(gx_device_pdf *pdev, |
1000 | | pdf_font_resource_t **ppdfont, const pdf_char_glyph_pairs_t *cgp, |
1001 | | pdf_char_proc_t **ppcp, gs_glyph glyph, gs_char char_code, |
1002 | | gs_font *font) |
1003 | 0 | { |
1004 | 0 | charproc_compatibility_data_t data; |
1005 | 0 | int code; |
1006 | |
|
1007 | 0 | data.cgp = cgp; |
1008 | 0 | data.pdfont = *ppdfont; |
1009 | 0 | data.char_code = char_code; |
1010 | 0 | data.glyph = glyph; |
1011 | 0 | data.font = font; |
1012 | 0 | pdev->find_resource_param = &data; |
1013 | 0 | code = pdf_find_same_charproc_aux(pdev, ppdfont, ppcp); |
1014 | 0 | pdev->find_resource_param = NULL; |
1015 | 0 | *ppdfont = data.pdfont; |
1016 | 0 | return code; |
1017 | 0 | } |
1018 | | |
1019 | | static bool |
1020 | | pdf_is_charproc_defined(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, gs_char ch) |
1021 | 0 | { |
1022 | 0 | pdf_char_proc_ownership_t *pcpo; |
1023 | |
|
1024 | 0 | for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) { |
1025 | 0 | if (pcpo->char_code == ch) |
1026 | 0 | return true; |
1027 | 0 | } |
1028 | 0 | return false; |
1029 | 0 | } |
1030 | | |
1031 | | static int |
1032 | | complete_adding_char(gx_device_pdf *pdev, gs_font *font, |
1033 | | gs_glyph glyph, gs_char ch, pdf_char_proc_t *pcp, |
1034 | | const gs_const_string *gnstr) |
1035 | 0 | { |
1036 | 0 | pdf_font_resource_t *pdfont; |
1037 | 0 | double *real_widths; |
1038 | 0 | byte *glyph_usage; |
1039 | 0 | int char_cache_size, width_cache_size; |
1040 | 0 | pdf_encoding_element_t *pet; |
1041 | 0 | int code; |
1042 | |
|
1043 | 0 | code = pdf_attached_font_resource(pdev, font, &pdfont, |
1044 | 0 | &glyph_usage, &real_widths, &char_cache_size, &width_cache_size); |
1045 | 0 | if (code < 0) |
1046 | 0 | return code; |
1047 | 0 | code = pdf_attach_charproc(pdev, pdfont, pcp, glyph, ch, gnstr); |
1048 | 0 | if (code < 0) |
1049 | 0 | return code; |
1050 | 0 | if (ch >= char_cache_size || ch >= width_cache_size) |
1051 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1052 | 0 | pet = &pdfont->u.simple.Encoding[ch]; |
1053 | 0 | pdfont->Widths[ch] = pcp->real_width.x; |
1054 | 0 | real_widths[ch * 2 ] = pcp->real_width.x; |
1055 | 0 | real_widths[ch * 2 + 1] = pcp->real_width.y; |
1056 | 0 | glyph_usage[ch / 8] |= 0x80 >> (ch & 7); |
1057 | 0 | pdfont->used[ch >> 3] |= 0x80 >> (ch & 7); |
1058 | 0 | if (pdfont->u.simple.v != NULL && font->WMode) { |
1059 | 0 | pdfont->u.simple.v[ch].x = pcp->v.x; |
1060 | 0 | pdfont->u.simple.v[ch].y = pcp->v.x; |
1061 | 0 | } |
1062 | 0 | pet->glyph = glyph; |
1063 | 0 | pet->str = *gnstr; |
1064 | 0 | pet->is_difference = true; |
1065 | 0 | if (pdfont->u.simple.LastChar < (int)ch) |
1066 | 0 | pdfont->u.simple.LastChar = (int)ch; |
1067 | 0 | if (pdfont->u.simple.FirstChar > (int)ch) |
1068 | 0 | pdfont->u.simple.FirstChar = (int)ch; |
1069 | 0 | return 0; |
1070 | 0 | } |
1071 | | |
1072 | | static int |
1073 | | pdf_char_widths_from_charprocs(gx_device_pdf *pdev, gs_font *font) |
1074 | 0 | { |
1075 | 0 | pdf_font_resource_t *pdfont; |
1076 | 0 | double *real_widths; |
1077 | 0 | byte *glyph_usage; |
1078 | 0 | int char_cache_size, width_cache_size; |
1079 | 0 | pdf_char_proc_ownership_t *pcpo; |
1080 | 0 | int code; |
1081 | |
|
1082 | 0 | code = pdf_attached_font_resource(pdev, font, &pdfont, |
1083 | 0 | &glyph_usage, &real_widths, &char_cache_size, &width_cache_size); |
1084 | 0 | if (code < 0) |
1085 | 0 | return code; |
1086 | 0 | for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) { |
1087 | 0 | pdf_char_proc_t *pcp = pcpo->char_proc; |
1088 | 0 | gs_char ch = pcpo->char_code; |
1089 | |
|
1090 | 0 | real_widths[ch * 2 ] = pcp->real_width.x; |
1091 | 0 | real_widths[ch * 2 + 1] = pcp->real_width.y; |
1092 | 0 | glyph_usage[ch / 8] |= 0x80 >> (ch & 7); |
1093 | 0 | } |
1094 | 0 | return 0; |
1095 | 0 | } |
1096 | | |
1097 | | /* |
1098 | | * Complete charproc accumulation for a Type 3 font. |
1099 | | */ |
1100 | | int |
1101 | | pdf_end_charproc_accum(gx_device_pdf *pdev, gs_font *font, const pdf_char_glyph_pairs_t *cgp, |
1102 | | gs_glyph glyph, gs_char output_char_code, const gs_const_string *gnstr) |
1103 | 0 | { |
1104 | 0 | int code; |
1105 | 0 | pdf_resource_t *pres = (pdf_resource_t *)pdev->accumulating_substream_resource; |
1106 | | /* We could use pdfont->u.simple.s.type3.char_procs insted the thing above |
1107 | | unless the font is defined recursively. |
1108 | | But we don't want such assumption. */ |
1109 | 0 | pdf_char_proc_t *pcp = (pdf_char_proc_t *)pres; |
1110 | 0 | pdf_font_resource_t *pdfont; |
1111 | 0 | gs_char ch = output_char_code; |
1112 | 0 | bool checking_glyph_variation = false; |
1113 | |
|
1114 | 0 | if (ch == GS_NO_CHAR) |
1115 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1116 | 0 | if (ch >= 256) |
1117 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1118 | 0 | code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL); |
1119 | 0 | if (code < 0) |
1120 | 0 | return code; |
1121 | 0 | if (pdfont != (pdf_font_resource_t *)pdev->font3) |
1122 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1123 | 0 | code = pdf_exit_substream(pdev); |
1124 | 0 | if (code < 0) |
1125 | 0 | return code; |
1126 | 0 | if (!(pdfont->used[ch >> 3] & (0x80 >> (ch & 7))) || |
1127 | 0 | !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) { |
1128 | | /* First appearence or not cached - check for duplicates. */ |
1129 | 0 | pdf_font_resource_t *pdfont1 = pdfont; |
1130 | |
|
1131 | 0 | checking_glyph_variation = true; |
1132 | | /* CAUTION : a possible font change. */ |
1133 | 0 | code = pdf_find_same_charproc(pdev, &pdfont, cgp, &pcp, glyph, ch, font); |
1134 | 0 | if (code < 0) |
1135 | 0 | return code; |
1136 | 0 | if (code != 0) { |
1137 | 0 | code = pdf_cancel_resource(pdev, pres, resourceCharProc); |
1138 | 0 | if (code < 0) |
1139 | 0 | return code; |
1140 | 0 | pdf_forget_resource(pdev, pres, resourceCharProc); |
1141 | 0 | if (pdfont1 != pdfont) { |
1142 | 0 | code = pdf_attach_font_resource(pdev, font, pdfont); |
1143 | 0 | if (code < 0) |
1144 | 0 | return code; |
1145 | 0 | code = pdf_char_widths_from_charprocs(pdev, font); |
1146 | 0 | if (code < 0) |
1147 | 0 | return code; |
1148 | 0 | } |
1149 | 0 | pdev->charproc_just_accumulated = true; |
1150 | 0 | return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr); |
1151 | 0 | } |
1152 | 0 | if (pdf_is_charproc_defined(pdev, pdfont, ch)) { |
1153 | | /* Encoding conflict after a font change. */ |
1154 | 0 | gs_font *base_font = font, *below; |
1155 | |
|
1156 | 0 | while ((below = base_font->base) != base_font && |
1157 | 0 | base_font->procs.same_font(base_font, below, FONT_SAME_OUTLINES)) |
1158 | 0 | base_font = below; |
1159 | 0 | code = pdf_make_font3_resource(pdev, base_font, &pdfont); |
1160 | 0 | if (code < 0) |
1161 | 0 | return code; |
1162 | 0 | code = pdf_attach_font_resource(pdev, font, pdfont); |
1163 | 0 | if (code < 0) |
1164 | 0 | return code; |
1165 | 0 | } |
1166 | 0 | } |
1167 | 0 | pdf_reserve_object_id(pdev, pres, 0); |
1168 | 0 | if (checking_glyph_variation) |
1169 | 0 | pdev->charproc_just_accumulated = true; |
1170 | 0 | return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr); |
1171 | 0 | } |
1172 | | |
1173 | | /* Add procsets to substream Resources. */ |
1174 | | int |
1175 | | pdf_add_procsets(cos_dict_t *pcd, pdf_procset_t procsets) |
1176 | 0 | { |
1177 | 0 | char str[5 + 7 + 7 + 7 + 5 + 2]; |
1178 | 0 | cos_value_t v; |
1179 | |
|
1180 | 0 | strcpy(str, "[/PDF"); |
1181 | 0 | if (procsets & ImageB) |
1182 | 0 | strcat(str, "/ImageB"); |
1183 | 0 | if (procsets & ImageC) |
1184 | 0 | strcat(str, "/ImageC"); |
1185 | 0 | if (procsets & ImageI) |
1186 | 0 | strcat(str, "/ImageI"); |
1187 | 0 | if (procsets & Text) |
1188 | 0 | strcat(str, "/Text"); |
1189 | 0 | strcat(str, "]"); |
1190 | 0 | cos_string_value(&v, (byte *)str, strlen(str)); |
1191 | 0 | return cos_dict_put_c_key(pcd, "/ProcSet", &v); |
1192 | 0 | } |
1193 | | |
1194 | | /* Add a resource to substream Resources. */ |
1195 | | int |
1196 | | pdf_add_resource(gx_device_pdf *pdev, cos_dict_t *pcd, const char *key, pdf_resource_t *pres) |
1197 | 0 | { |
1198 | 0 | if (pcd != 0) { |
1199 | 0 | const cos_value_t *v = cos_dict_find(pcd, (const byte *)key, strlen(key)); |
1200 | 0 | cos_dict_t *list; |
1201 | 0 | int code; |
1202 | 0 | char buf[10 + (sizeof(long) * 8 / 3 + 1)], buf1[sizeof(pres->rname) + 1]; |
1203 | |
|
1204 | 0 | if (pdev->ForOPDFRead && !pres->global && pdev->accumulating_a_global_object) { |
1205 | 0 | pres->global = true; |
1206 | 0 | code = cos_dict_put_c_key_bool((cos_dict_t *)pres->object, "/.Global", true); |
1207 | 0 | if (code < 0) |
1208 | 0 | return code; |
1209 | 0 | } |
1210 | 0 | gs_sprintf(buf, "%ld 0 R\n", pres->object->id); |
1211 | 0 | if (v != NULL) { |
1212 | 0 | if (v->value_type != COS_VALUE_OBJECT && |
1213 | 0 | v->value_type != COS_VALUE_RESOURCE) |
1214 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1215 | 0 | list = (cos_dict_t *)v->contents.object; |
1216 | 0 | if (list->cos_procs != &cos_dict_procs) |
1217 | 0 | return_error(gs_error_unregistered); /* Must not happen. */ |
1218 | 0 | } else { |
1219 | 0 | list = cos_dict_alloc(pdev, "pdf_add_resource"); |
1220 | 0 | if (list == NULL) |
1221 | 0 | return_error(gs_error_VMerror); |
1222 | 0 | code = cos_dict_put_c_key_object((cos_dict_t *)pcd, key, (cos_object_t *)list); |
1223 | 0 | if (code < 0) |
1224 | 0 | return code; |
1225 | 0 | } |
1226 | 0 | buf1[0] = '/'; |
1227 | 0 | strcpy(buf1 + 1, pres->rname); |
1228 | 0 | return cos_dict_put_string(list, (const byte *)buf1, strlen(buf1), |
1229 | 0 | (const byte *)buf, strlen(buf)); |
1230 | 0 | } |
1231 | 0 | return 0; |
1232 | 0 | } |