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: gdevpdti.c,v 1.53 2005/10/12 08:16:50 leonardo Exp $ */
18 /* Bitmap font implementation for pdfwrite */
19 #include "memory_.h"
20 #include "string_.h"
21 #include "gx.h"
22 #include "gxpath.h"
23 #include "gserrors.h"
24 #include "gsutil.h"
25 #include "gdevpdfx.h"
26 #include "gdevpdfg.h"
27 #include "gdevpdtf.h"
28 #include "gdevpdti.h"
29 #include "gdevpdts.h"
30 #include "gdevpdtw.h"
31 #include "gdevpdtt.h"
32 #include "gdevpdfo.h"
33
34 /* ---------------- Private ---------------- */
35
36 /* Define the structure for a CharProc pseudo-resource. */
37 /*typedef struct pdf_char_proc_s pdf_char_proc_t;*/ /* gdevpdfx.h */
38 struct pdf_char_proc_s {
39 pdf_resource_common(pdf_char_proc_t);
40 pdf_font_resource_t *font;
41 pdf_char_proc_t *char_next; /* next char_proc for same font */
42 int y_offset; /* of character (0,0) */
43 gs_char char_code;
44 gs_const_string char_name;
45 gs_point real_width; /* Not used with synthesised bitmap fonts. */
46 gs_point v; /* Not used with synthesised bitmap fonts. */
47 };
48
49 /* The descriptor is public for pdf_resource_type_structs. */
50 gs_public_st_suffix_add2_string1(st_pdf_char_proc, pdf_char_proc_t,
51 "pdf_char_proc_t", pdf_char_proc_enum_ptrs, pdf_char_proc_reloc_ptrs,
52 st_pdf_resource, font, char_next, char_name);
53
54 /* Define the state structure for tracking bitmap fonts. */
55 /*typedef struct pdf_bitmap_fonts_s pdf_bitmap_fonts_t;*/
56 struct pdf_bitmap_fonts_s {
57 pdf_font_resource_t *open_font; /* current Type 3 synthesized font */
58 bool use_open_font; /* if false, start new open_font */
59 long bitmap_encoding_id;
60 int max_embedded_code; /* max Type 3 code used */
61 };
62 gs_private_st_ptrs1(st_pdf_bitmap_fonts, pdf_bitmap_fonts_t,
63 "pdf_bitmap_fonts_t", pdf_bitmap_fonts_enum_ptrs,
64 pdf_bitmap_fonts_reloc_ptrs, open_font);
65
66 inline private long
pdf_char_proc_id(const pdf_char_proc_t * pcp)67 pdf_char_proc_id(const pdf_char_proc_t *pcp)
68 {
69 return pdf_resource_id((const pdf_resource_t *)pcp);
70 }
71
72 /* Assign a code for a char_proc. */
73 private int
assign_char_code(gx_device_pdf * pdev,int width)74 assign_char_code(gx_device_pdf * pdev, int width)
75 {
76 pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
77 pdf_font_resource_t *pdfont = pbfs->open_font; /* Type 3 */
78 int c, code;
79
80 if (pbfs->bitmap_encoding_id == 0)
81 pbfs->bitmap_encoding_id = pdf_obj_ref(pdev);
82 if (pdfont == 0 || pdfont->u.simple.LastChar == 255 ||
83 !pbfs->use_open_font
84 ) {
85 /* Start a new synthesized font. */
86 char *pc;
87
88 code = pdf_font_type3_alloc(pdev, &pdfont, pdf_write_contents_bitmap);
89 if (code < 0)
90 return code;
91 pdfont->u.simple.s.type3.bitmap_font = true;
92 if (pbfs->open_font == 0)
93 pdfont->rname[0] = 0;
94 else
95 strcpy(pdfont->rname, pbfs->open_font->rname);
96 pdfont->u.simple.s.type3.FontBBox.p.x = 0;
97 pdfont->u.simple.s.type3.FontBBox.p.y = 0;
98 pdfont->u.simple.s.type3.FontBBox.q.x = 1000;
99 pdfont->u.simple.s.type3.FontBBox.q.y = 1000;
100 gs_make_identity(&pdfont->u.simple.s.type3.FontMatrix);
101 /*
102 * We "increment" the font name as a radix-26 "number".
103 * This cannot possibly overflow.
104 */
105 for (pc = pdfont->rname; *pc == 'Z'; ++pc)
106 *pc = '@';
107 if ((*pc)++ == 0)
108 *pc = 'A', pc[1] = 0;
109 pbfs->open_font = pdfont;
110 pbfs->use_open_font = true;
111 pdfont->u.simple.FirstChar = 0;
112 }
113 c = ++(pdfont->u.simple.LastChar);
114 pdfont->Widths[c] = psdf_round(pdev->char_width.x, 100, 10); /* See
115 pdf_write_Widths about rounding. We need to provide
116 a compatible data for Tj. */
117 if (c > pbfs->max_embedded_code)
118 pbfs->max_embedded_code = c;
119
120 /* Synthezise ToUnicode CMap :*/
121 { gs_text_enum_t *pte = pdev->pte;
122 gs_font *font = pte->current_font;
123
124 code = pdf_add_ToUnicode(pdev, font, pdfont, pte->returned.current_glyph, c);
125 if (code < 0)
126 return code;
127 }
128 return c;
129 }
130
131 /* Write the contents of a Type 3 bitmap or vector font resource. */
132 int
pdf_write_contents_bitmap(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)133 pdf_write_contents_bitmap(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
134 {
135 stream *s = pdev->strm;
136 const pdf_char_proc_t *pcp;
137 long diff_id = 0;
138 int code;
139
140 if (pdfont->u.simple.s.type3.bitmap_font)
141 diff_id = pdev->text->bitmap_fonts->bitmap_encoding_id;
142 else {
143 /* See comment in pdf_write_encoding. */
144 diff_id = pdf_obj_ref(pdev);
145 }
146 code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
147 if (code < 0)
148 return code;
149 stream_puts(s, "/CharProcs <<");
150 /* Write real characters. */
151 for (pcp = pdfont->u.simple.s.type3.char_procs; pcp;
152 pcp = pcp->char_next
153 ) {
154 if (pdfont->u.simple.s.type3.bitmap_font)
155 pprintld2(s, "/a%ld %ld 0 R\n", (long)pcp->char_code,
156 pdf_char_proc_id(pcp));
157 else {
158 pdf_put_name(pdev, pcp->char_name.data, pcp->char_name.size);
159 pprintld1(s, " %ld 0 R\n", pdf_char_proc_id(pcp));
160 }
161 }
162 stream_puts(s, ">>");
163 pprintg6(s, "/FontMatrix[%g %g %g %g %g %g]",
164 (float)pdfont->u.simple.s.type3.FontMatrix.xx,
165 (float)pdfont->u.simple.s.type3.FontMatrix.xy,
166 (float)pdfont->u.simple.s.type3.FontMatrix.yx,
167 (float)pdfont->u.simple.s.type3.FontMatrix.yy,
168 (float)pdfont->u.simple.s.type3.FontMatrix.tx,
169 (float)pdfont->u.simple.s.type3.FontMatrix.ty);
170 code = pdf_finish_write_contents_type3(pdev, pdfont);
171 if (code < 0)
172 return code;
173 s = pdev->strm; /* pdf_finish_write_contents_type3 changes pdev->strm . */
174 if (!pdfont->u.simple.s.type3.bitmap_font && diff_id > 0) {
175 code = pdf_write_encoding(pdev, pdfont, diff_id, 0);
176 if (code < 0)
177 return code;
178 }
179 return 0;
180 }
181
182 /* ---------------- Public ---------------- */
183
184 /*
185 * Allocate and initialize bookkeeping for bitmap fonts.
186 */
187 pdf_bitmap_fonts_t *
pdf_bitmap_fonts_alloc(gs_memory_t * mem)188 pdf_bitmap_fonts_alloc(gs_memory_t *mem)
189 {
190 pdf_bitmap_fonts_t *pbfs =
191 gs_alloc_struct(mem, pdf_bitmap_fonts_t, &st_pdf_bitmap_fonts,
192 "pdf_bitmap_fonts_alloc");
193
194 if (pbfs == 0)
195 return 0;
196 memset(pbfs, 0, sizeof(*pbfs));
197 pbfs->max_embedded_code = -1;
198 return pbfs;
199 }
200
201 /*
202 * Update text state at the end of a page.
203 */
204 void
pdf_close_text_page(gx_device_pdf * pdev)205 pdf_close_text_page(gx_device_pdf *pdev)
206 {
207 /*
208 * When Acrobat Reader 3 prints a file containing a Type 3 font with a
209 * non-standard Encoding, it apparently only emits the subset of the
210 * font actually used on the page. Thus, if the "Download Fonts Once"
211 * option is selected, characters not used on the page where the font
212 * first appears will not be defined, and hence will print as blank if
213 * used on subsequent pages. Thus, we can't allow a Type 3 font to
214 * add additional characters on subsequent pages.
215 */
216 if (pdev->CompatibilityLevel <= 1.2)
217 pdev->text->bitmap_fonts->use_open_font = false;
218 }
219
220 /* Return the Y offset for a bitmap character image. */
221 int
pdf_char_image_y_offset(const gx_device_pdf * pdev,int x,int y,int h)222 pdf_char_image_y_offset(const gx_device_pdf *pdev, int x, int y, int h)
223 {
224 const pdf_text_data_t *const ptd = pdev->text;
225 gs_point pt;
226 int max_off, off;
227
228 pdf_text_position(pdev, &pt);
229 if (x < pt.x)
230 return 0;
231 max_off = (ptd->bitmap_fonts->open_font == 0 ? 0 :
232 ptd->bitmap_fonts->open_font->u.simple.s.type3.max_y_offset);
233 off = (y + h) - (int)(pt.y + 0.5);
234 if (off < -max_off || off > max_off)
235 off = 0;
236 return off;
237 }
238
239 /* Begin a CharProc for a synthesized font. */
240 private int
pdf_begin_char_proc_generic(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,gs_id id,gs_char char_code,pdf_char_proc_t ** ppcp,pdf_stream_position_t * ppos)241 pdf_begin_char_proc_generic(gx_device_pdf * pdev, pdf_font_resource_t *pdfont,
242 gs_id id, gs_char char_code,
243 pdf_char_proc_t ** ppcp, pdf_stream_position_t * ppos)
244 {
245 pdf_resource_t *pres;
246 pdf_char_proc_t *pcp;
247 int code;
248
249 code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
250 if (code < 0)
251 return code;
252 pcp = (pdf_char_proc_t *) pres;
253 pcp->font = pdfont;
254 pcp->char_next = pdfont->u.simple.s.type3.char_procs;
255 pdfont->u.simple.s.type3.char_procs = pcp;
256 pcp->char_code = char_code;
257 pres->object->written = true;
258 pcp->char_name.data = 0;
259 pcp->char_name.size = 0;
260
261 {
262 stream *s = pdev->strm;
263
264 /*
265 * The resource file is positionable, so rather than use an
266 * object reference for the length, we'll go back and fill it in
267 * at the end of the definition. Take 1M as the longest
268 * definition we can handle. (This used to be 10K, but there was
269 * a real file that exceeded this limit.)
270 */
271 stream_puts(s, "<</Length >>stream\n");
272 ppos->start_pos = stell(s);
273 }
274 code = pdf_begin_encrypt(pdev, &pdev->strm, pres->object->id);
275 if (code < 0)
276 return code;
277 *ppcp = pcp;
278 return 0;
279 }
280
281 /* Begin a CharProc for a synthesized (bitmap) font. */
282 int
pdf_begin_char_proc(gx_device_pdf * pdev,int w,int h,int x_width,int y_offset,gs_id id,pdf_char_proc_t ** ppcp,pdf_stream_position_t * ppos)283 pdf_begin_char_proc(gx_device_pdf * pdev, int w, int h, int x_width,
284 int y_offset, gs_id id, pdf_char_proc_t ** ppcp,
285 pdf_stream_position_t * ppos)
286 {
287 int char_code = assign_char_code(pdev, x_width);
288 pdf_bitmap_fonts_t *const pbfs = pdev->text->bitmap_fonts;
289 pdf_font_resource_t *font = pbfs->open_font; /* Type 3 */
290 int code = pdf_begin_char_proc_generic(pdev, font, id, char_code, ppcp, ppos);
291
292 if (code < 0)
293 return code;
294 (*ppcp)->y_offset = y_offset;
295 font->u.simple.s.type3.FontBBox.p.y =
296 min(font->u.simple.s.type3.FontBBox.p.y, y_offset);
297 font->u.simple.s.type3.FontBBox.q.x =
298 max(font->u.simple.s.type3.FontBBox.q.x, w);
299 font->u.simple.s.type3.FontBBox.q.y =
300 max(font->u.simple.s.type3.FontBBox.q.y, y_offset + h);
301 font->u.simple.s.type3.max_y_offset =
302 max(font->u.simple.s.type3.max_y_offset, h + (h >> 2));
303 return 0;
304 }
305
306 /* End a CharProc. */
307 int
pdf_end_char_proc(gx_device_pdf * pdev,pdf_stream_position_t * ppos)308 pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos)
309 {
310 stream *s;
311 long start_pos, end_pos, length;
312
313 pdf_end_encrypt(pdev);
314 s = pdev->strm;
315 start_pos = ppos->start_pos;
316 end_pos = stell(s);
317 length = end_pos - start_pos;
318 if (length > 999999)
319 return_error(gs_error_limitcheck);
320 sseek(s, start_pos - 15);
321 pprintd1(s, "%d", length);
322 sseek(s, end_pos);
323 stream_puts(s, "endstream\n");
324 pdf_end_separate(pdev);
325 return 0;
326 }
327
328 /* Put out a reference to an image as a character in a synthesized font. */
329 int
pdf_do_char_image(gx_device_pdf * pdev,const pdf_char_proc_t * pcp,const gs_matrix * pimat)330 pdf_do_char_image(gx_device_pdf * pdev, const pdf_char_proc_t * pcp,
331 const gs_matrix * pimat)
332 {
333 pdf_font_resource_t *pdfont = pcp->font;
334 byte ch = pcp->char_code;
335 pdf_text_state_values_t values;
336
337 values.character_spacing = 0;
338 values.pdfont = pdfont;
339 values.size = 1;
340 values.matrix = *pimat;
341 values.matrix.ty -= pcp->y_offset;
342 values.render_mode = 0;
343 values.word_spacing = 0;
344 pdf_set_text_state_values(pdev, &values);
345 pdf_append_chars(pdev, &ch, 1, pdfont->Widths[ch] * pimat->xx, 0.0, false);
346 return 0;
347 }
348
349 /*
350 * Write the Encoding for bitmap fonts, if needed.
351 */
352 int
pdf_write_bitmap_fonts_Encoding(gx_device_pdf * pdev)353 pdf_write_bitmap_fonts_Encoding(gx_device_pdf *pdev)
354 {
355 pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
356
357 if (pbfs->bitmap_encoding_id) {
358 stream *s;
359 int i;
360
361 pdf_open_separate(pdev, pbfs->bitmap_encoding_id);
362 s = pdev->strm;
363 /*
364 * Even though the PDF reference documentation says that a
365 * BaseEncoding key is required unless the encoding is
366 * "based on the base font's encoding" (and there is no base
367 * font in this case), Acrobat 2.1 gives an error if the
368 * BaseEncoding key is present.
369 */
370 stream_puts(s, "<</Type/Encoding/Differences[0");
371 for (i = 0; i <= pbfs->max_embedded_code; ++i) {
372 if (!(i & 15))
373 stream_puts(s, "\n");
374 pprintd1(s, "/a%d", i);
375 }
376 stream_puts(s, "\n] >>\n");
377 pdf_end_separate(pdev);
378 pbfs->bitmap_encoding_id = 0;
379 }
380 return 0;
381 }
382
383 /*
384 * Start charproc accumulation for a Type 3 font.
385 */
386 int
pdf_start_charproc_accum(gx_device_pdf * pdev)387 pdf_start_charproc_accum(gx_device_pdf *pdev)
388 {
389 pdf_char_proc_t *pcp;
390 pdf_resource_t *pres;
391 int code = pdf_enter_substream(pdev, resourceCharProc, gs_next_ids(pdev->memory, 1),
392 &pres, false, pdev->CompressFonts);
393
394 if (code < 0)
395 return code;
396 pcp = (pdf_char_proc_t *)pres;
397 pcp->char_next = NULL;
398 pcp->font = NULL;
399 pcp->char_code = GS_NO_CHAR;
400 pcp->char_name.data = NULL;
401 pcp->char_name.size = 0;
402 return 0;
403 }
404
405 /*
406 * Install charproc accumulator for a Type 3 font.
407 */
408 int
pdf_set_charproc_attrs(gx_device_pdf * pdev,gs_font * font,const double * pw,int narg,gs_text_cache_control_t control,gs_char ch,gs_const_string * gnstr)409 pdf_set_charproc_attrs(gx_device_pdf *pdev, gs_font *font, const double *pw, int narg,
410 gs_text_cache_control_t control, gs_char ch, gs_const_string *gnstr)
411 {
412 pdf_font_resource_t *pdfont;
413 pdf_resource_t *pres = pdev->accumulating_substream_resource;
414 pdf_char_proc_t *pcp;
415 int code;
416
417 code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
418 if (code < 0)
419 return code;
420 pcp = (pdf_char_proc_t *)pres;
421 pcp->char_next = NULL;
422 pcp->font = pdfont;
423 pcp->char_code = ch;
424 pcp->char_name = *gnstr;
425 pcp->real_width.x = pw[font->WMode && narg > 6 ? 6 : 0];
426 pcp->real_width.y = pw[font->WMode && narg > 6 ? 7 : 1];
427 pcp->v.x = (narg > 8 ? pw[8] : 0);
428 pcp->v.y = (narg > 8 ? pw[9] : 0);
429 if (control == TEXT_SET_CHAR_WIDTH) {
430 /* PLRM 5.7.1 "BuildGlyph" reads : "Normally, it is unnecessary and
431 undesirable to initialize the current color parameter, because show
432 is defined to paint glyphs with the current color."
433 However comparefiles/Bug687044.ps doesn't follow that. */
434 pdev->skip_colors = false;
435 pprintg2(pdev->strm, "%g %g d0\n", (float)pw[0], (float)pw[1]);
436 } else {
437 pdev->skip_colors = true;
438 pprintg6(pdev->strm, "%g %g %g %g %g %g d1\n",
439 (float)pw[0], (float)pw[1], (float)pw[2],
440 (float)pw[3], (float)pw[4], (float)pw[5]);
441 pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
442 }
443 pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
444 pdev->font3 = (pdf_resource_t *)pdfont;
445 return 0;
446 }
447
448 /*
449 * Open a stream object in the temporary file.
450 */
451
452 int
pdf_open_aside(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id id,pdf_resource_t ** ppres,bool reserve_object_id,int options)453 pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype,
454 gs_id id, pdf_resource_t **ppres, bool reserve_object_id, int options)
455 {
456 int code;
457 pdf_resource_t *pres;
458 stream *s, *save_strm = pdev->strm;
459 pdf_data_writer_t writer;
460 static const pdf_filter_names_t fnames = {
461 PDF_FILTER_NAMES
462 };
463
464 pdev->streams.save_strm = pdev->strm;
465 code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id),
466 pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1);
467 if (code < 0)
468 return code;
469 cos_become(pres->object, cos_type_stream);
470 s = cos_write_stream_alloc((cos_stream_t *)pres->object, pdev, "pdf_enter_substream");
471 if (s == 0)
472 return_error(gs_error_VMerror);
473 pdev->strm = s;
474 code = pdf_append_data_stream_filters(pdev, &writer,
475 options | DATA_STREAM_NOLENGTH, pres->object->id);
476 if (code < 0) {
477 pdev->strm = save_strm;
478 return code;
479 }
480 code = pdf_put_filters((cos_dict_t *)pres->object, pdev, writer.binary.strm, &fnames);
481 if (code < 0) {
482 pdev->strm = save_strm;
483 return code;
484 }
485 pdev->strm = writer.binary.strm;
486 *ppres = pres;
487 return 0;
488 }
489
490 /*
491 * Close a stream object in the temporary file.
492 */
493 int
pdf_close_aside(gx_device_pdf * pdev)494 pdf_close_aside(gx_device_pdf *pdev)
495 {
496 /* We should call pdf_end_data here, but we don't want to put pdf_data_writer_t
497 into pdf_substream_save stack to simplify garbager descriptors.
498 Use a lower level functions instead that. */
499 stream *s = pdev->strm;
500 int status = s_close_filters(&s, cos_write_stream_from_pipeline(s));
501 cos_stream_t *pcs = cos_stream_from_pipeline(s);
502 int code = 0;
503
504 if (status < 0)
505 code = gs_note_error(gs_error_ioerror);
506 pcs->is_open = false;
507 sclose(s);
508 pdev->strm = pdev->streams.save_strm;
509 return code;
510 }
511
512 /*
513 * Enter the substream accumulation mode.
514 */
515 int
pdf_enter_substream(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id id,pdf_resource_t ** ppres,bool reserve_object_id,bool compress)516 pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype,
517 gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress)
518 {
519 int sbstack_ptr = pdev->sbstack_depth;
520 pdf_resource_t *pres;
521 stream *save_strm = pdev->strm;
522 int code;
523
524 if (pdev->sbstack_depth >= pdev->sbstack_size)
525 return_error(gs_error_unregistered); /* Must not happen. */
526 if (pdev->sbstack[sbstack_ptr].text_state == 0) {
527 pdev->sbstack[sbstack_ptr].text_state = pdf_text_state_alloc(pdev->pdf_memory);
528 if (pdev->sbstack[sbstack_ptr].text_state == 0)
529 return_error(gs_error_VMerror);
530 }
531 code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id,
532 (compress ? DATA_STREAM_COMPRESS : 0));
533 if (code < 0)
534 return code;
535 code = pdf_save_viewer_state(pdev, NULL);
536 if (code < 0) {
537 pdev->strm = save_strm;
538 return code;
539 }
540 pdev->sbstack[sbstack_ptr].context = pdev->context;
541 pdf_text_state_copy(pdev->sbstack[sbstack_ptr].text_state, pdev->text->text_state);
542 pdf_set_text_state_default(pdev->text->text_state);
543 pdev->sbstack[sbstack_ptr].clip_path = pdev->clip_path;
544 pdev->clip_path = 0;
545 pdev->sbstack[sbstack_ptr].clip_path_id = pdev->clip_path_id;
546 pdev->clip_path_id = pdev->no_clip_path_id;
547 pdev->sbstack[sbstack_ptr].vgstack_bottom = pdev->vgstack_bottom;
548 pdev->vgstack_bottom = pdev->vgstack_depth;
549 pdev->sbstack[sbstack_ptr].strm = save_strm;
550 pdev->sbstack[sbstack_ptr].procsets = pdev->procsets;
551 pdev->sbstack[sbstack_ptr].substream_Resources = pdev->substream_Resources;
552 pdev->sbstack[sbstack_ptr].skip_colors = pdev->skip_colors;
553 pdev->sbstack[sbstack_ptr].font3 = pdev->font3;
554 pdev->sbstack[sbstack_ptr].accumulating_substream_resource = pdev->accumulating_substream_resource;
555 pdev->sbstack[sbstack_ptr].charproc_just_accumulated = pdev->charproc_just_accumulated;
556 pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object;
557 pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict;
558 pdev->sbstack[sbstack_ptr].objname = pdev->objname;
559 pdev->skip_colors = false;
560 pdev->charproc_just_accumulated = false;
561 pdev->pres_soft_mask_dict = NULL;
562 pdev->objname.data = NULL;
563 pdev->objname.size = 0;
564 /* Do not reset pdev->accumulating_a_global_object - it inherits. */
565 pdev->sbstack_depth++;
566 pdev->procsets = 0;
567 pdev->font3 = 0;
568 pdev->context = PDF_IN_STREAM;
569 pdev->accumulating_substream_resource = pres;
570 pdf_reset_graphics(pdev);
571 *ppres = pres;
572 return 0;
573 }
574
575 /*
576 * Exit the substream accumulation mode.
577 */
578 int
pdf_exit_substream(gx_device_pdf * pdev)579 pdf_exit_substream(gx_device_pdf *pdev)
580 {
581 int code, code1;
582 int sbstack_ptr;
583
584 if (pdev->sbstack_depth <= 0)
585 return_error(gs_error_unregistered); /* Must not happen. */
586 code = pdf_open_contents(pdev, PDF_IN_STREAM);
587 sbstack_ptr = pdev->sbstack_depth - 1;
588 while (pdev->vgstack_depth > pdev->vgstack_bottom) {
589 code1 = pdf_restore_viewer_state(pdev, pdev->strm);
590 if (code >= 0)
591 code = code1;
592 }
593 if (pdev->clip_path != 0)
594 gx_path_free(pdev->clip_path, "pdf_end_charproc_accum");
595 code1 = pdf_close_aside(pdev);
596 if (code1 < 0 && code >= 0)
597 code = code1;
598 pdev->context = pdev->sbstack[sbstack_ptr].context;
599 pdf_text_state_copy(pdev->text->text_state, pdev->sbstack[sbstack_ptr].text_state);
600 pdev->clip_path = pdev->sbstack[sbstack_ptr].clip_path;
601 pdev->sbstack[sbstack_ptr].clip_path = 0;
602 pdev->clip_path_id = pdev->sbstack[sbstack_ptr].clip_path_id;
603 pdev->vgstack_bottom = pdev->sbstack[sbstack_ptr].vgstack_bottom;
604 pdev->strm = pdev->sbstack[sbstack_ptr].strm;
605 pdev->sbstack[sbstack_ptr].strm = 0;
606 pdev->procsets = pdev->sbstack[sbstack_ptr].procsets;
607 pdev->substream_Resources = pdev->sbstack[sbstack_ptr].substream_Resources;
608 pdev->sbstack[sbstack_ptr].substream_Resources = 0;
609 pdev->skip_colors = pdev->sbstack[sbstack_ptr].skip_colors;
610 pdev->font3 = pdev->sbstack[sbstack_ptr].font3;
611 pdev->sbstack[sbstack_ptr].font3 = 0;
612 pdev->accumulating_substream_resource = pdev->sbstack[sbstack_ptr].accumulating_substream_resource;
613 pdev->sbstack[sbstack_ptr].accumulating_substream_resource = 0;
614 pdev->charproc_just_accumulated = pdev->sbstack[sbstack_ptr].charproc_just_accumulated;
615 pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object;
616 pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict;
617 pdev->objname = pdev->sbstack[sbstack_ptr].objname;
618 pdev->sbstack_depth = sbstack_ptr;
619 code1 = pdf_restore_viewer_state(pdev, NULL);
620 if (code1 < 0 && code >= 0)
621 code = code1;
622 return code;
623 }
624
625 private bool
pdf_is_same_charproc1(gx_device_pdf * pdev,pdf_char_proc_t * pcp0,pdf_char_proc_t * pcp1)626 pdf_is_same_charproc1(gx_device_pdf * pdev, pdf_char_proc_t *pcp0, pdf_char_proc_t *pcp1)
627 {
628 if (pcp0->char_code != pcp1->char_code)
629 return false; /* We need same encoding. */
630 if (pcp0->font->u.simple.Encoding[pcp0->char_code].glyph !=
631 pcp1->font->u.simple.Encoding[pcp1->char_code].glyph)
632 return false; /* We need same encoding. */
633 if (bytes_compare(pcp0->char_name.data, pcp0->char_name.size,
634 pcp1->char_name.data, pcp1->char_name.size))
635 return false; /* We need same encoding. */
636 if (pcp0->real_width.x != pcp1->real_width.x)
637 return false;
638 if (pcp0->real_width.y != pcp1->real_width.y)
639 return false;
640 if (pcp0->v.x != pcp1->v.x)
641 return false;
642 if (pcp0->v.y != pcp1->v.y)
643 return false;
644 if (pcp0->font->u.simple.s.type3.bitmap_font != pcp1->font->u.simple.s.type3.bitmap_font)
645 return false;
646 if (memcmp(&pcp0->font->u.simple.s.type3.FontMatrix, &pcp1->font->u.simple.s.type3.FontMatrix,
647 sizeof(pcp0->font->u.simple.s.type3.FontMatrix)))
648 return false;
649 return pdf_check_encoding_compatibility(pcp1->font, pdev->cgp->s, pdev->cgp->num_all_chars);
650 }
651
652 private int
pdf_is_same_charproc(gx_device_pdf * pdev,pdf_resource_t * pres0,pdf_resource_t * pres1)653 pdf_is_same_charproc(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
654 {
655 return pdf_is_same_charproc1(pdev, (pdf_char_proc_t *)pres0, (pdf_char_proc_t *)pres1);
656 }
657
658 private int
pdf_find_same_charproc(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,const pdf_char_glyph_pairs_t * cgp,pdf_char_proc_t ** ppcp)659 pdf_find_same_charproc(gx_device_pdf *pdev,
660 pdf_font_resource_t *pdfont, const pdf_char_glyph_pairs_t *cgp,
661 pdf_char_proc_t **ppcp)
662 {
663 pdf_char_proc_t *pcp;
664 int code;
665
666 pdev->cgp = cgp;
667 for (pcp = pdfont->u.simple.s.type3.char_procs; pcp != NULL; pcp = pcp->char_next) {
668 if (*ppcp != pcp && pdf_is_same_charproc1(pdev, *ppcp, pcp)) {
669 cos_object_t *pco0 = pcp->object;
670 cos_object_t *pco1 = (*ppcp)->object;
671
672 code = pco0->cos_procs->equal(pco0, pco1, pdev);
673 if (code < 0)
674 return code;
675 if (code) {
676 *ppcp = pcp;
677 pdev->cgp = NULL;
678 return 1;
679 }
680 }
681 }
682 pcp = *ppcp;
683 code = pdf_find_same_resource(pdev, resourceCharProc, (pdf_resource_t **)ppcp, pdf_is_same_charproc);
684 pdev->cgp = NULL;
685 if (code <= 0)
686 return code;
687 /* fixme : do we need more checks here ? */
688 return 1;
689 }
690
691 private bool
pdf_is_charproc_defined(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,gs_char ch)692 pdf_is_charproc_defined(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, gs_char ch)
693 {
694 pdf_char_proc_t *pcp;
695
696 for (pcp = pdfont->u.simple.s.type3.char_procs; pcp != NULL; pcp = pcp->char_next) {
697 if (pcp->char_code == ch) {
698 return true;
699 }
700 }
701 return false;
702 }
703
704 /*
705 * Complete charproc accumulation for a Type 3 font.
706 */
707 int
pdf_end_charproc_accum(gx_device_pdf * pdev,gs_font * font,const pdf_char_glyph_pairs_t * cgp)708 pdf_end_charproc_accum(gx_device_pdf *pdev, gs_font *font, const pdf_char_glyph_pairs_t *cgp)
709 {
710 int code;
711 pdf_resource_t *pres = (pdf_resource_t *)pdev->accumulating_substream_resource;
712 /* We could use pdfont->u.simple.s.type3.char_procs insted the thing above
713 unless the font is defined recursively.
714 But we don't want such assumption. */
715 pdf_char_proc_t *pcp = (pdf_char_proc_t *)pres;
716 pdf_font_resource_t *pdfont;
717 gs_char ch = pcp->char_code;
718 double *real_widths;
719 byte *glyph_usage;
720 int char_cache_size, width_cache_size;
721 gs_glyph glyph0;
722 bool checking_glyph_variation = false;
723 int i;
724
725 code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
726 if (code < 0)
727 return code;
728 if (pdfont != (pdf_font_resource_t *)pdev->font3)
729 return_error(gs_error_unregistered); /* Must not happen. */
730 if (ch == GS_NO_CHAR)
731 return_error(gs_error_unregistered); /* Must not happen. */
732 if (ch >= 256)
733 return_error(gs_error_unregistered); /* Must not happen. */
734 code = pdf_exit_substream(pdev);
735 if (code < 0)
736 return code;
737 if (pdfont->used[ch >> 3] & (0x80 >> (ch & 7))) {
738 if (!(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) {
739 checking_glyph_variation = true;
740 code = pdf_find_same_charproc(pdev, pdfont, cgp, &pcp);
741 if (code < 0)
742 return code;
743 if (code != 0) {
744 code = pdf_cancel_resource(pdev, pres, resourceCharProc);
745 if (code < 0)
746 return code;
747 pdf_forget_resource(pdev, pres, resourceCharProc);
748 if (pcp->font != pdfont) {
749 code = pdf_attach_font_resource(pdev, font, pcp->font);
750 if (code < 0)
751 return code;
752 }
753 pdev->charproc_just_accumulated = true;
754 return 0;
755 }
756 if (pdf_is_charproc_defined(pdev, pdfont, ch)) {
757 gs_font *base_font = font, *below;
758
759 while ((below = base_font->base) != base_font &&
760 base_font->procs.same_font(base_font, below, FONT_SAME_OUTLINES))
761 base_font = below;
762 code = pdf_make_font3_resource(pdev, base_font, &pdfont);
763 if (code < 0)
764 return code;
765 code = pdf_attach_font_resource(pdev, font, pdfont);
766 if (code < 0)
767 return code;
768 }
769 }
770 }
771 pdf_reserve_object_id(pdev, pres, 0);
772 code = pdf_attached_font_resource(pdev, font, &pdfont,
773 &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
774 if (code < 0)
775 return code;
776 if (ch >= char_cache_size || ch >= width_cache_size)
777 return_error(gs_error_unregistered); /* Must not happen. */
778 if (checking_glyph_variation)
779 pdev->charproc_just_accumulated = true;
780 glyph0 = font->procs.encode_char(font, ch, GLYPH_SPACE_NAME);
781 pcp->char_next = pdfont->u.simple.s.type3.char_procs;
782 pdfont->u.simple.s.type3.char_procs = pcp;
783 pcp->font = pdfont;
784 pdfont->Widths[ch] = pcp->real_width.x;
785 real_widths[ch * 2 ] = pcp->real_width.x;
786 real_widths[ch * 2 + 1] = pcp->real_width.y;
787 glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
788 pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
789 if (pdfont->u.simple.v != NULL && font->WMode) {
790 pdfont->u.simple.v[ch].x = pcp->v.x;
791 pdfont->u.simple.v[ch].y = pcp->v.x;
792 }
793 for (i = 0; i < 256; i++) {
794 gs_glyph glyph = font->procs.encode_char(font, i,
795 font->FontType == ft_user_defined ? GLYPH_SPACE_NOGEN
796 : GLYPH_SPACE_NAME);
797
798 if (glyph == glyph0) {
799 real_widths[i * 2 ] = real_widths[ch * 2 ];
800 real_widths[i * 2 + 1] = real_widths[ch * 2 + 1];
801 glyph_usage[i / 8] |= 0x80 >> (i & 7);
802 pdfont->used[i >> 3] |= 0x80 >> (i & 7);
803 pdfont->u.simple.v[i] = pdfont->u.simple.v[ch];
804 pdfont->Widths[i] = pdfont->Widths[ch];
805 }
806 }
807 return 0;
808 }
809
810 /* Add procsets to substream Resources. */
811 int
pdf_add_procsets(cos_dict_t * pcd,pdf_procset_t procsets)812 pdf_add_procsets(cos_dict_t *pcd, pdf_procset_t procsets)
813 {
814 char str[5 + 7 + 7 + 7 + 5 + 2];
815 cos_value_t v;
816
817 strcpy(str, "[/PDF");
818 if (procsets & ImageB)
819 strcat(str, "/ImageB");
820 if (procsets & ImageC)
821 strcat(str, "/ImageC");
822 if (procsets & ImageI)
823 strcat(str, "/ImageI");
824 if (procsets & Text)
825 strcat(str, "/Text");
826 strcat(str, "]");
827 cos_string_value(&v, (byte *)str, strlen(str));
828 return cos_dict_put_c_key(pcd, "/ProcSet", &v);
829 }
830
831 /* Add a resource to substream Resources. */
832 int
pdf_add_resource(gx_device_pdf * pdev,cos_dict_t * pcd,const char * key,pdf_resource_t * pres)833 pdf_add_resource(gx_device_pdf *pdev, cos_dict_t *pcd, const char *key, pdf_resource_t *pres)
834 {
835 if (pcd != 0) {
836 const cos_value_t *v = cos_dict_find(pcd, (const byte *)key, strlen(key));
837 cos_dict_t *list;
838 int code;
839 char buf[10 + (sizeof(long) * 8 / 3 + 1)], buf1[sizeof(pres->rname) + 1];
840
841 if (pdev->ForOPDFRead && !pres->global && pdev->accumulating_a_global_object) {
842 pres->global = true;
843 code = cos_dict_put_c_key_bool((cos_dict_t *)pres->object, "/.Global", true);
844 if (code < 0)
845 return code;
846 }
847 sprintf(buf, "%ld 0 R\n", pres->object->id);
848 if (v != NULL) {
849 if (v->value_type != COS_VALUE_OBJECT &&
850 v->value_type != COS_VALUE_RESOURCE)
851 return_error(gs_error_unregistered); /* Must not happen. */
852 list = (cos_dict_t *)v->contents.object;
853 if (list->cos_procs != &cos_dict_procs)
854 return_error(gs_error_unregistered); /* Must not happen. */
855 } else {
856 list = cos_dict_alloc(pdev, "pdf_add_resource");
857 if (list == NULL)
858 return_error(gs_error_VMerror);
859 code = cos_dict_put_c_key_object((cos_dict_t *)pcd, key, (cos_object_t *)list);
860 if (code < 0)
861 return code;
862 }
863 buf1[0] = '/';
864 strcpy(buf1 + 1, pres->rname);
865 return cos_dict_put_string(list, (const byte *)buf1, strlen(buf1),
866 (const byte *)buf, strlen(buf));
867 }
868 return 0;
869 }
870
871