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