xref: /plan9/sys/src/cmd/gs/src/gdevpdti.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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