Coverage Report

Created: 2026-10-28 08:05

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