Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/vector/gdevpdti.c
Line
Count
Source (jump to first uncovered line)
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
295k
{
72
295k
    return pdf_resource_id((const pdf_resource_t *)pcp);
73
295k
}
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
134k
{
79
134k
    pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
80
134k
    pdf_font_resource_t *pdfont = pbfs->open_font; /* Type 3 */
81
134k
    int i, c = 0, code;
82
134k
    uint operation = pte->text.operation;
83
84
134k
    if (pbfs->bitmap_encoding_id == 0)
85
1.80k
        pbfs->bitmap_encoding_id = pdf_obj_ref(pdev);
86
134k
    if (pdfont == 0 || pdfont->u.simple.LastChar == 255 ||
87
134k
        !pbfs->use_open_font
88
134k
        ) {
89
        /* Start a new synthesized font. */
90
2.38k
        char *pc;
91
92
2.38k
        code = pdf_font_type3_alloc(pdev, &pdfont, pdf_write_contents_bitmap);
93
2.38k
        if (code < 0)
94
0
            return code;
95
2.38k
        pdfont->u.simple.s.type3.bitmap_font = true;
96
2.38k
        if (pbfs->open_font == 0)
97
1.80k
            pdfont->rname[0] = 0;
98
581
        else
99
581
            strcpy(pdfont->rname, pbfs->open_font->rname);
100
2.38k
        pdfont->u.simple.s.type3.FontBBox.p.x = 0;
101
2.38k
        pdfont->u.simple.s.type3.FontBBox.p.y = 0;
102
2.38k
        pdfont->u.simple.s.type3.FontBBox.q.x = 0;
103
2.38k
        pdfont->u.simple.s.type3.FontBBox.q.y = 0;
104
2.38k
        pdfont->mark_glyph = NULL;
105
2.38k
        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
2.38k
        for (pc = pdfont->rname; *pc == 'Z'; ++pc)
111
0
            *pc = '@';
112
2.38k
        if ((*pc)++ == 0)
113
1.80k
            *pc = 'A', pc[1] = 0;
114
2.38k
        pbfs->open_font = pdfont;
115
2.38k
        pbfs->use_open_font = true;
116
2.38k
        pdfont->u.simple.FirstChar = 255;
117
2.38k
    }
118
134k
    if ((operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) ||
119
134k
        (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR))) {
120
134k
        unsigned char p = *pte->text.data.bytes;
121
134k
        unsigned char index = p / 8, bit = 0x01 << (p % 8);
122
123
134k
        if (pdfont->used[index] & bit) {
124
10.6M
            for (i = 0;i < 256;i++) {
125
10.6M
                index = i / 8;
126
10.6M
                bit = 0x01 << (i % 8);
127
10.6M
                if (!(pdfont->used[index] & bit)) {
128
121k
                    c = i;
129
121k
                    break;
130
121k
                }
131
10.6M
            }
132
121k
        } else
133
12.2k
            c = p;
134
134k
        pdfont->used[index] |= bit;
135
134k
        if (c > pdfont->u.simple.LastChar)
136
86.2k
            pdfont->u.simple.LastChar = c;
137
138
134k
    } 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
134k
    if (c < pdfont->u.simple.FirstChar)
146
3.83k
        pdfont->u.simple.FirstChar = c;
147
148
134k
    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
134k
    if (c > pbfs->max_embedded_code)
152
61.4k
        pbfs->max_embedded_code = c;
153
154
134k
    return c;
155
134k
}
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
3.29k
{
161
3.29k
    stream *s = pdev->strm;
162
3.29k
    const pdf_char_proc_ownership_t *pcpo;
163
3.29k
    int64_t diff_id = 0;
164
3.29k
    int code;
165
166
3.29k
    if (pdfont->u.simple.s.type3.bitmap_font)
167
2.38k
        diff_id = pdev->text->bitmap_fonts->bitmap_encoding_id;
168
915
    else {
169
        /* See comment in pdf_write_encoding. */
170
915
        diff_id = pdf_obj_ref(pdev);
171
915
    }
172
3.29k
    code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
173
3.29k
    if (code < 0)
174
0
        return code;
175
3.29k
    stream_puts(s, "/CharProcs <<");
176
    /* Write real characters. */
177
151k
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo;
178
147k
         pcpo = pcpo->char_next
179
147k
         ) {
180
147k
        if (pdfont->u.simple.s.type3.bitmap_font)
181
134k
            pprinti64d2(s, "/a%"PRId64" %"PRId64" 0 R\n", pcpo->char_code,
182
134k
                      pdf_char_proc_id(pcpo->char_proc));
183
13.7k
        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
147k
        pdf_record_usage_by_parent(pdev, pdf_char_proc_id(pcpo->char_proc), pdfont->object->id);
188
147k
    }
189
3.29k
    stream_puts(s, ">>");
190
3.29k
    pprintg6(s, "/FontMatrix[%g %g %g %g %g %g]",
191
3.29k
            (float)pdfont->u.simple.s.type3.FontMatrix.xx,
192
3.29k
            (float)pdfont->u.simple.s.type3.FontMatrix.xy,
193
3.29k
            (float)pdfont->u.simple.s.type3.FontMatrix.yx,
194
3.29k
            (float)pdfont->u.simple.s.type3.FontMatrix.yy,
195
3.29k
            (float)pdfont->u.simple.s.type3.FontMatrix.tx,
196
3.29k
            (float)pdfont->u.simple.s.type3.FontMatrix.ty);
197
3.29k
    code = pdf_finish_write_contents_type3(pdev, pdfont);
198
3.29k
    if (code < 0)
199
0
        return code;
200
3.29k
    if (!pdfont->u.simple.s.type3.bitmap_font && diff_id > 0) {
201
915
        code = pdf_write_encoding(pdev, pdfont, diff_id, 0);
202
915
        if (code < 0)
203
0
            return code;
204
915
    }
205
3.29k
    return 0;
206
3.29k
}
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
34.0k
{
216
34.0k
    pdf_bitmap_fonts_t *pbfs =
217
34.0k
        gs_alloc_struct(mem, pdf_bitmap_fonts_t, &st_pdf_bitmap_fonts,
218
34.0k
                        "pdf_bitmap_fonts_alloc");
219
220
34.0k
    if (pbfs == 0)
221
0
        return 0;
222
34.0k
    memset(pbfs, 0, sizeof(*pbfs));
223
34.0k
    pbfs->max_embedded_code = -1;
224
34.0k
    return pbfs;
225
34.0k
}
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
45.3k
{
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
45.3k
    if (pdev->CompatibilityLevel <= 1.2)
243
33.1k
        pdev->text->bitmap_fonts->use_open_font = false;
244
45.3k
}
245
246
int
247
pdf_charproc_y_offset(pdf_char_proc_t *pcp)
248
1.67M
{
249
1.67M
    return pcp->y_offset;
250
1.67M
}
251
252
int
253
pdf_charproc_x_offset(pdf_char_proc_t *pcp)
254
1.67M
{
255
1.67M
    return pcp->x_offset;
256
1.67M
}
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
232k
{
263
232k
    pdf_char_proc_ownership_t *pcpo;
264
232k
    bool duplicate_char_name = false;
265
266
14.2M
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
267
14.1M
        if (pcpo->glyph == glyph && pcpo->char_code == char_code)
268
81.0k
            return 0;
269
14.1M
    }
270
151k
    if (!pdfont->u.simple.s.type3.bitmap_font) {
271
616k
        for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
272
598k
            if (!bytes_compare(pcpo->char_name.data, pcpo->char_name.size, gnstr->data, gnstr->size)) {
273
37
                duplicate_char_name = true;
274
37
                break;
275
37
            }
276
598k
        }
277
17.5k
    }
278
151k
    pcpo = gs_alloc_struct(pdev->pdf_memory,
279
151k
            pdf_char_proc_ownership_t, &st_pdf_char_proc_ownership, "pdf_attach_charproc");
280
281
151k
    if (pcpo == NULL)
282
0
        return_error(gs_error_VMerror);
283
151k
    pcpo->font = pdfont;
284
151k
    pcpo->char_next = pdfont->u.simple.s.type3.char_procs;
285
151k
    pdfont->u.simple.s.type3.char_procs = pcpo;
286
151k
    pcpo->char_proc = pcp;
287
151k
    pcpo->font_next = pcp->owner_fonts;
288
151k
    pcp->owner_fonts = pcpo;
289
151k
    pcpo->char_code = char_code;
290
151k
    pcpo->glyph = glyph;
291
151k
    if (gnstr == NULL) {
292
134k
        pcpo->char_name.data = 0;
293
134k
        pcpo->char_name.size = 0;
294
134k
    } else {
295
17.5k
        if (gnstr->size > 0) {
296
17.5k
            pcpo->char_name.data = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, gnstr->size, "storage for charproc name");
297
17.5k
            if (pcpo->char_name.data == NULL)
298
0
                return_error(gs_error_VMerror);
299
17.5k
            memcpy(pcpo->char_name.data, gnstr->data, gnstr->size);
300
17.5k
        }
301
17.5k
        pcpo->char_name.size = gnstr->size;
302
17.5k
    }
303
151k
    pcpo->duplicate_char_name = duplicate_char_name;
304
151k
    return 0;
305
151k
}
306
307
int
308
pdf_free_charproc_ownership(gx_device_pdf * pdev, pdf_resource_t *pres)
309
3.34k
{
310
3.34k
    pdf_char_proc_ownership_t *next, *pcpo = (pdf_char_proc_ownership_t *)pres;
311
312
155k
    while (pcpo) {
313
151k
        next = pcpo->char_next;
314
151k
        if(pcpo->char_name.size != 0 && pcpo->char_name.data) {
315
17.5k
            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
17.5k
            pcpo->char_name.data = (byte *)0L;
319
17.5k
            pcpo->char_name.size = 0;
320
17.5k
        }
321
151k
        gs_free_object(pdev->pdf_memory, pcpo, "Free CharProc");
322
151k
        pcpo = next;
323
151k
    }
324
3.34k
    return 0;
325
3.34k
}
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
134k
{
333
134k
    gs_char char_code = 0;
334
134k
    pdf_bitmap_fonts_t *const pbfs = pdev->text->bitmap_fonts;
335
134k
    pdf_font_resource_t *font;
336
134k
    pdf_resource_t *pres;
337
134k
    pdf_char_proc_t *pcp;
338
134k
    int code;
339
    /* This code added to store PCL bitmap glyphs in type 3 fonts where possible */
340
134k
    gs_glyph glyph = GS_NO_GLYPH;
341
134k
    gs_const_string str2, *str = NULL;
342
134k
    gs_show_enum *show_enum = (gs_show_enum *)pdev->pte;
343
134k
    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
134k
    int allowed_op = (show_enum->text.operation &
348
134k
        (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
134k
    if ((show_enum->current_font->FontType == ft_user_defined ||
361
134k
        show_enum->current_font->FontType == ft_PDF_user_defined ||
362
134k
        show_enum->current_font->FontType == ft_PCL_user_defined ||
363
134k
        show_enum->current_font->FontType == ft_MicroType ||
364
134k
        show_enum->current_font->FontType == ft_GL2_stick_user_defined ||
365
134k
        show_enum->current_font->FontType == ft_GL2_531) && allowed_op &&
366
134k
        show_enum->current_font->FontMatrix.xx == 1 && show_enum->current_font->FontMatrix.xy == 0 &&
367
134k
        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
134k
    } else {
438
134k
        char_code = assign_char_code(pdev, pdev->pte);
439
134k
        font = pbfs->open_font; /* Type 3 */
440
134k
    }
441
442
134k
    code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
443
134k
    if (code < 0)
444
0
        return code;
445
134k
    pcp = (pdf_char_proc_t *) pres;
446
134k
    code = pdf_attach_charproc(pdev, font, pcp, glyph, char_code, str);
447
134k
    if (code < 0)
448
0
        return code;
449
134k
    pres->object->written = true;
450
134k
    {
451
134k
        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
134k
        stream_puts(s, "<</Length       >>stream\n");
461
134k
        ppos->start_pos = stell(s);
462
134k
    }
463
134k
    code = pdf_begin_encrypt(pdev, &pdev->strm, pres->object->id);
464
134k
    if (code < 0)
465
0
        return code;
466
134k
    pcp->y_offset = y_offset;
467
134k
    pcp->x_offset = x_offset;
468
134k
    font->u.simple.s.type3.FontBBox.q.x =
469
134k
        max(font->u.simple.s.type3.FontBBox.q.x, w);
470
134k
    font->u.simple.s.type3.FontBBox.q.y =
471
134k
        max(font->u.simple.s.type3.FontBBox.q.y, y_offset + h);
472
134k
    font->u.simple.s.type3.max_y_offset =
473
134k
        max(font->u.simple.s.type3.max_y_offset, h + (h >> 2));
474
134k
    pcp->real_width.x = w;
475
134k
    pcp->real_width.y = y_offset + h;
476
134k
    *ppcp = pcp;
477
134k
    return 0;
478
134k
}
479
480
/* End a CharProc. */
481
int
482
pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos)
483
134k
{
484
134k
    stream *s;
485
134k
    gs_offset_t start_pos, end_pos, length;
486
487
134k
    if (pdf_end_encrypt(pdev))
488
0
        s_close_filters(&pdev->strm, pdev->strm->strm);
489
490
134k
    s = pdev->strm;
491
134k
    start_pos = ppos->start_pos;
492
134k
    end_pos = stell(s);
493
134k
    length = end_pos - start_pos;
494
134k
    if (length > 999999)
495
0
        return_error(gs_error_limitcheck);
496
134k
    sseek(s, start_pos - 15);
497
134k
    pprintd1(s, "%d", length);
498
134k
    sseek(s, end_pos);
499
134k
    if (pdev->PDFA != 0)
500
0
        stream_puts(s, "\n");
501
134k
    stream_puts(s, "endstream\n");
502
134k
    pdf_end_separate(pdev, resourceCharProc);
503
134k
    return 0;
504
134k
}
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
35.1k
{
510
35.1k
    if (pdfont->mark_glyph == NULL) {
511
        /* Synthesised bitmap fonts pass here. */
512
33.1k
        return;
513
33.1k
    }
514
2.03k
    if (pdfont->u.simple.Encoding != NULL) {
515
2.03k
         int i;
516
517
522k
         for (i = 0; i < 256; i++)
518
520k
             if (pdfont->u.simple.Encoding[i].glyph != GS_NO_GLYPH)
519
83.7k
                pdfont->mark_glyph(memory, pdfont->u.simple.Encoding[i].glyph, pdfont->mark_glyph_data);
520
2.03k
     }
521
2.03k
    if (pdfont->FontType == ft_user_defined ||
522
2.03k
        pdfont->FontType == ft_PDF_user_defined ||
523
2.03k
        pdfont->FontType == ft_PCL_user_defined ||
524
2.03k
        pdfont->FontType == ft_MicroType ||
525
2.03k
        pdfont->FontType == ft_GL2_stick_user_defined ||
526
2.03k
        pdfont->FontType == ft_GL2_531) {
527
320
        const pdf_char_proc_ownership_t *pcpo = pdfont->u.simple.s.type3.char_procs;
528
529
6.58k
        for (; pcpo != NULL; pcpo = pcpo->font_next)
530
6.26k
            pdfont->mark_glyph(memory, pcpo->glyph, pdfont->mark_glyph_data);
531
320
    }
532
2.03k
}
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.81M
{
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.81M
    const pdf_char_proc_ownership_t * pcpo = pcp->owner_fonts;
543
1.81M
    pdf_font_resource_t *pdfont = pcpo->font;
544
1.81M
    byte ch = pcpo->char_code;
545
1.81M
    pdf_text_state_values_t values;
546
547
1.81M
    values.character_spacing = 0;
548
1.81M
    values.pdfont = pdfont;
549
1.81M
    values.size = 1;
550
1.81M
    values.matrix = *pimat;
551
1.81M
    values.render_mode = pdev->pte->pgs->text_rendering_mode;
552
1.81M
    values.word_spacing = 0;
553
1.81M
    pdf_set_text_state_values(pdev, &values);
554
1.81M
    pdf_bitmap_char_update_bbox(pdev, pcp->x_offset, pcp->y_offset, pcp->real_width.x, pcp->real_width.y);
555
1.81M
    pdf_append_chars(pdev, &ch, 1, pdfont->Widths[ch] * pimat->xx, 0.0, false);
556
1.81M
    return 0;
557
1.81M
}
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
34.0k
{
565
34.0k
    pdf_bitmap_fonts_t *pbfs;
566
567
34.0k
    if (pdev->text == NULL || pdev->text->bitmap_fonts == NULL)
568
0
        return 0;
569
570
34.0k
    pbfs = pdev->text->bitmap_fonts;
571
572
34.0k
    if (pbfs->bitmap_encoding_id) {
573
1.80k
        stream *s;
574
1.80k
        int i;
575
576
1.80k
        pdf_open_separate(pdev, pbfs->bitmap_encoding_id, resourceEncoding);
577
1.80k
        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.80k
        stream_puts(s, "<</Type/Encoding/Differences[0");
586
137k
        for (i = 0; i <= pbfs->max_embedded_code; ++i) {
587
135k
            if (!(i & 15))
588
9.36k
                stream_puts(s, "\n");
589
135k
            pprintd1(s, "/a%d", i);
590
135k
        }
591
1.80k
        stream_puts(s, "\n] >>\n");
592
1.80k
        pdf_end_separate(pdev, resourceEncoding);
593
1.80k
        pbfs->bitmap_encoding_id = 0;
594
1.80k
    }
595
34.0k
    return 0;
596
34.0k
}
597
598
/*
599
 * Start charproc accumulation for a Type 3 font.
600
 */
601
int
602
pdf_start_charproc_accum(gx_device_pdf *pdev)
603
98.6k
{
604
98.6k
    pdf_char_proc_t *pcp;
605
98.6k
    pdf_resource_t *pres;
606
98.6k
    int id = gs_next_ids(pdev->memory, 1);
607
98.6k
    int code = pdf_enter_substream(pdev, resourceCharProc, id,
608
98.6k
                                   &pres, false, pdev->CompressFonts);
609
610
98.6k
    if (code < 0)
611
0
       return code;
612
98.6k
    pres->rid = id;
613
98.6k
    pcp = (pdf_char_proc_t *)pres;
614
98.6k
    pcp->owner_fonts = NULL;
615
98.6k
    return 0;
616
98.6k
}
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
83.2k
{
625
83.2k
    pdf_font_resource_t *pdfont;
626
83.2k
    pdf_resource_t *pres = pdev->accumulating_substream_resource;
627
83.2k
    pdf_char_proc_t *pcp;
628
83.2k
    int code;
629
630
83.2k
    if (pres == NULL)
631
0
        return_error(gs_error_undefined);
632
83.2k
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
633
83.2k
    if (code < 0)
634
0
        return code;
635
83.2k
    pcp = (pdf_char_proc_t *)pres;
636
83.2k
    pcp->owner_fonts = NULL;
637
83.2k
    pcp->real_width.x = pw[font->WMode && narg > 6 ? 6 : 0];
638
83.2k
    pcp->real_width.y = pw[font->WMode && narg > 6 ? 7 : 1];
639
83.2k
    pcp->v.x = (narg > 8 ? pw[8] : 0);
640
83.2k
    pcp->v.y = (narg > 8 ? pw[9] : 0);
641
83.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
74.4k
        pdev->skip_colors = false;
647
74.4k
        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
74.4k
        if (font->FontType == ft_PCL_user_defined || font->FontType == ft_GL2_stick_user_defined
653
74.4k
            || font->FontType == ft_GL2_531 || font->FontType == ft_MicroType)
654
0
            pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
655
74.4k
    } else {
656
8.81k
        double d;
657
8.81k
        pdev->skip_colors = true;
658
8.81k
        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.81k
        if (pw[5] < pw[3]) {
664
31
            d = pw[5];
665
31
            pw[5] = pw[3];
666
31
            pw[3] = d;
667
31
        }
668
8.81k
        pprintg6(pdev->strm, "%g %g %g %g %g %g d1\n",
669
8.81k
            (float)pw[0], (float)0.0, (float)pw[2],
670
8.81k
            (float)pw[3], (float)pw[4], (float)pw[5]);
671
8.81k
        pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
672
8.81k
    }
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
83.2k
    if (scale_100) {
680
83.2k
    code = stream_puts(pdev->strm, "0.01 0 0 0.01 0 0 cm\n");
681
83.2k
    if (code < 0)
682
0
        return code;
683
83.2k
    }
684
83.2k
    return 0;
685
83.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
179k
{
695
179k
    int code;
696
179k
    pdf_resource_t *pres;
697
179k
    stream *s, *save_strm = pdev->strm;
698
179k
    pdf_data_writer_t writer;
699
179k
    static const pdf_filter_names_t fnames = {
700
179k
        PDF_FILTER_NAMES
701
179k
    };
702
703
179k
    pdev->streams.save_strm = pdev->strm;
704
705
179k
    if (rtype >= NUM_RESOURCE_TYPES)
706
42.5k
        rtype = resourceOther;
707
179k
    code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id),
708
179k
                pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1);
709
179k
    if (code < 0)
710
0
        return code;
711
179k
    cos_become(pres->object, cos_type_stream);
712
179k
    s = cos_write_stream_alloc((cos_stream_t *)pres->object, pdev, "pdf_enter_substream");
713
179k
    if (s == 0)
714
0
        return_error(gs_error_VMerror);
715
179k
    pdev->strm = s;
716
179k
    code = pdf_append_data_stream_filters(pdev, &writer,
717
179k
                             options | DATA_STREAM_NOLENGTH, pres->object->id);
718
179k
    if (code < 0) {
719
0
        pdev->strm = save_strm;
720
0
        return code;
721
0
    }
722
179k
    code = pdf_put_filters((cos_dict_t *)pres->object, pdev, writer.binary.strm, &fnames);
723
179k
    if (code < 0) {
724
0
        pdev->strm = save_strm;
725
0
        return code;
726
0
    }
727
179k
    pdev->strm = writer.binary.strm;
728
179k
    *ppres = pres;
729
179k
    return 0;
730
179k
}
731
732
/*
733
 * Close a stream object in the temporary file.
734
 */
735
int
736
pdf_close_aside(gx_device_pdf *pdev)
737
179k
{
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
179k
    stream *s = pdev->strm;
742
179k
    cos_stream_t *pcs = cos_stream_from_pipeline(s);
743
179k
    int status = s_close_filters(&s, NULL);
744
745
179k
    pdev->strm = pdev->streams.save_strm;
746
179k
    if (status < 0)
747
0
         return(gs_note_error(gs_error_ioerror));
748
749
179k
    if (!pcs)
750
0
        return gs_note_error(gs_error_ioerror);
751
752
179k
    pcs->is_open = false;
753
179k
    return 0;
754
179k
}
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
136k
{
763
136k
    int sbstack_ptr = pdev->sbstack_depth;
764
136k
    pdf_resource_t *pres;
765
136k
    stream *save_strm = pdev->strm;
766
136k
    int code;
767
768
136k
    if (pdev->sbstack_depth >= pdev->sbstack_size)
769
0
        return_error(gs_error_unregistered); /* Must not happen. */
770
136k
    if (pdev->sbstack[sbstack_ptr].text_state == 0) {
771
136k
        pdev->sbstack[sbstack_ptr].text_state = pdf_text_state_alloc(pdev->pdf_memory);
772
136k
        if (pdev->sbstack[sbstack_ptr].text_state == 0)
773
0
            return_error(gs_error_VMerror);
774
136k
    }
775
136k
    code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id,
776
136k
                    (compress ? DATA_STREAM_COMPRESS : 0));
777
136k
    if (code < 0)
778
0
        return code;
779
136k
    code = pdf_save_viewer_state(pdev, NULL);
780
136k
    if (code < 0) {
781
0
        pdev->strm = save_strm;
782
0
        return code;
783
0
    }
784
136k
    pdev->sbstack[sbstack_ptr].context = pdev->context;
785
136k
    pdf_text_state_copy(pdev->sbstack[sbstack_ptr].text_state, pdev->text->text_state);
786
136k
    pdf_set_text_state_default(pdev->text->text_state);
787
136k
    pdev->sbstack[sbstack_ptr].clip_path = pdev->clip_path;
788
136k
    pdev->clip_path = 0;
789
136k
    pdev->sbstack[sbstack_ptr].clip_path_id = pdev->clip_path_id;
790
136k
    pdev->clip_path_id = pdev->no_clip_path_id;
791
136k
    pdev->sbstack[sbstack_ptr].vgstack_bottom = pdev->vgstack_bottom;
792
136k
    pdev->vgstack_bottom = pdev->vgstack_depth;
793
136k
    pdev->sbstack[sbstack_ptr].strm = save_strm;
794
136k
    pdev->sbstack[sbstack_ptr].procsets = pdev->procsets;
795
136k
    pdev->sbstack[sbstack_ptr].substream_Resources = pdev->substream_Resources;
796
136k
    pdev->sbstack[sbstack_ptr].skip_colors = pdev->skip_colors;
797
136k
    pdev->sbstack[sbstack_ptr].font3 = pdev->font3;
798
136k
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = pdev->accumulating_substream_resource;
799
136k
    pdev->sbstack[sbstack_ptr].charproc_just_accumulated = pdev->charproc_just_accumulated;
800
136k
    pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object;
801
136k
    pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict;
802
136k
    pdev->sbstack[sbstack_ptr].objname = pdev->objname;
803
136k
    pdev->sbstack[sbstack_ptr].last_charpath_op = pdev->last_charpath_op;
804
136k
    pdev->skip_colors = false;
805
136k
    pdev->charproc_just_accumulated = false;
806
136k
    pdev->pres_soft_mask_dict = NULL;
807
136k
    pdev->objname.data = NULL;
808
136k
    pdev->objname.size = 0;
809
    /* Do not reset pdev->accumulating_a_global_object - it inherits. */
810
136k
    pdev->sbstack_depth++;
811
136k
    pdev->procsets = 0;
812
136k
    pdev->font3 = 0;
813
136k
    pdev->context = PDF_IN_STREAM;
814
136k
    pdev->accumulating_substream_resource = pres;
815
136k
    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
136k
    if (rtype != resourceXObject)
820
135k
        pdf_reset_graphics(pdev);
821
1.30k
    else {
822
1.30k
        if (pdev->vg_initial_set)
823
1.30k
            pdev->state.blend_mode = pdev->vg_initial.blend_mode;
824
1.30k
    }
825
136k
    *ppres = pres;
826
136k
    return 0;
827
136k
}
828
829
/*
830
 * Exit the substream accumulation mode.
831
 */
832
int
833
pdf_exit_substream(gx_device_pdf *pdev)
834
136k
{
835
136k
    int code, code1;
836
136k
    int sbstack_ptr;
837
838
136k
    if (pdev->sbstack_depth <= 0)
839
0
        return_error(gs_error_unregistered); /* Must not happen. */
840
136k
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
841
136k
    sbstack_ptr = pdev->sbstack_depth - 1;
842
138k
    while (pdev->vgstack_depth > pdev->vgstack_bottom) {
843
1.82k
        code1 = pdf_restore_viewer_state(pdev, pdev->strm);
844
1.82k
        if (code >= 0)
845
1.82k
            code = code1;
846
1.82k
    }
847
136k
    if (pdev->clip_path != 0)
848
1.82k
        gx_path_free(pdev->clip_path, "pdf_end_charproc_accum");
849
136k
    code1 = pdf_close_aside(pdev);
850
136k
    if (code1 < 0 && code >= 0)
851
0
        code = code1;
852
136k
    pdev->context = pdev->sbstack[sbstack_ptr].context;
853
136k
    pdf_text_state_copy(pdev->text->text_state, pdev->sbstack[sbstack_ptr].text_state);
854
136k
    gs_free_object(pdev->pdf_memory, pdev->sbstack[sbstack_ptr].text_state, "free text state for stream");
855
136k
    pdev->sbstack[sbstack_ptr].text_state = 0;
856
136k
    pdev->clip_path = pdev->sbstack[sbstack_ptr].clip_path;
857
136k
    pdev->sbstack[sbstack_ptr].clip_path = 0;
858
136k
    pdev->clip_path_id = pdev->sbstack[sbstack_ptr].clip_path_id;
859
136k
    pdev->vgstack_bottom = pdev->sbstack[sbstack_ptr].vgstack_bottom;
860
136k
    pdev->strm = pdev->sbstack[sbstack_ptr].strm;
861
136k
    pdev->sbstack[sbstack_ptr].strm = 0;
862
136k
    pdev->procsets = pdev->sbstack[sbstack_ptr].procsets;
863
136k
    pdev->substream_Resources = pdev->sbstack[sbstack_ptr].substream_Resources;
864
136k
    pdev->sbstack[sbstack_ptr].substream_Resources = 0;
865
136k
    pdev->skip_colors = pdev->sbstack[sbstack_ptr].skip_colors;
866
136k
    pdev->font3 = pdev->sbstack[sbstack_ptr].font3;
867
136k
    pdev->sbstack[sbstack_ptr].font3 = 0;
868
136k
    pdev->accumulating_substream_resource = pdev->sbstack[sbstack_ptr].accumulating_substream_resource;
869
136k
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = 0;
870
136k
    pdev->charproc_just_accumulated = pdev->sbstack[sbstack_ptr].charproc_just_accumulated;
871
136k
    pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object;
872
136k
    pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict;
873
136k
    pdev->objname = pdev->sbstack[sbstack_ptr].objname;
874
136k
    pdev->last_charpath_op = pdev->sbstack[sbstack_ptr].last_charpath_op;
875
136k
    pdev->sbstack_depth = sbstack_ptr;
876
136k
    code1 = pdf_restore_viewer_state(pdev, NULL);
877
136k
    if (code1 < 0 && code >= 0)
878
0
        code = code1;
879
136k
    return code;
880
136k
}
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
271k
{
885
271k
    if (pcp0->real_width.x != pcp1->real_width.x)
886
165k
        return false;
887
105k
    if (pcp0->real_width.y != pcp1->real_width.y)
888
0
        return false;
889
105k
    if (pcp0->v.x != pcp1->v.x)
890
0
        return false;
891
105k
    if (pcp0->v.y != pcp1->v.y)
892
0
        return false;
893
105k
    return true;
894
105k
}
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
155
{
907
155
    pdf_char_proc_ownership_t *pcpo;
908
909
1.21k
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
910
1.06k
        if (pcpo->char_code == char_code) {
911
2
            return true;
912
2
        }
913
1.06k
    }
914
153
    return false;
915
155
}
916
917
static int
918
pdf_is_charproc_compatible(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
919
155
{
920
155
    charproc_compatibility_data_t *data = (charproc_compatibility_data_t *)pdev->find_resource_param;
921
155
    pdf_char_proc_t *pcp0 = (pdf_char_proc_t *)pres0;
922
155
    pdf_char_proc_t *pcp1 = (pdf_char_proc_t *)pres1;
923
155
    pdf_font_resource_t *pdfont = data->pdfont;
924
155
    pdf_char_proc_ownership_t *pcpo;
925
155
    pdf_font_cache_elem_t **e;
926
155
    bool can_add_to_current_font = false, computed_can_add_to_current_font = false;
927
928
    /* Does it have same attributes ? */
929
155
    if (!pdf_is_same_charproc_attrs1(pdev, pcp0, pcp1))
930
0
        return 0;
931
    /* Is it from same font ? */
932
1.95k
    for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
933
1.80k
        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.80k
    }
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
155
    e = pdf_locate_font_cache_elem(pdev, data->font);
951
155
    if (e != NULL) {
952
1.95k
        for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
953
1.80k
            if (pcpo->char_code != data->char_code || pcpo->glyph != data->glyph)
954
1.73k
                continue; /* Need same Encoding to generate a proper ToUnicode. */
955
74
            if (pdfont->u.simple.s.type3.bitmap_font != pcpo->font->u.simple.s.type3.bitmap_font)
956
0
                continue;
957
74
            if (gs_matrix_compare(&pdfont->u.simple.s.type3.FontMatrix, &pcpo->font->u.simple.s.type3.FontMatrix))
958
25
                continue;
959
49
            if (data->cgp != NULL) {
960
47
                if (!pdf_check_encoding_compatibility(pcpo->font, data->cgp->s, data->cgp->num_all_chars))
961
0
                    continue;
962
47
            }
963
49
            if ((*e)->pdfont != pcpo->font)
964
49
                continue;
965
0
            data->pdfont = pcpo->font; /* Switch to the other font. */
966
0
            return 1;
967
49
        }
968
155
    }
969
    /* Check whether it can be added into the current font. */
970
155
    if (!computed_can_add_to_current_font)
971
155
        can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
972
155
    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
153
    return 1;
978
155
}
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
98.5k
{
984
98.5k
    pdf_char_proc_ownership_t *pcpo;
985
98.5k
    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
280k
    for (pcpo = (*ppdfont)->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
992
271k
        pdf_char_proc_t *pcp = pcpo->char_proc;
993
994
271k
        if (*ppcp != pcp && pdf_is_same_charproc_attrs1(pdev, *ppcp, pcp)) {
995
105k
            cos_object_t *pco0 = pcp->object;
996
105k
            cos_object_t *pco1 = (*ppcp)->object;
997
998
105k
            code = pco0->cos_procs->equal(pco0, pco1, pdev);
999
105k
            if (code < 0) {
1000
0
                return code;
1001
0
            }
1002
105k
            if (code) {
1003
89.1k
                *ppcp = pcp;
1004
89.1k
                return 1;
1005
89.1k
            }
1006
105k
        }
1007
271k
    }
1008
9.40k
    return pdf_find_same_resource(pdev, resourceCharProc, (pdf_resource_t **)ppcp, pdf_is_charproc_compatible);
1009
98.5k
}
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
98.5k
{
1016
98.5k
    charproc_compatibility_data_t data;
1017
98.5k
    int code;
1018
1019
98.5k
    data.cgp = cgp;
1020
98.5k
    data.pdfont = *ppdfont;
1021
98.5k
    data.char_code = char_code;
1022
98.5k
    data.glyph = glyph;
1023
98.5k
    data.font = font;
1024
98.5k
    pdev->find_resource_param = &data;
1025
98.5k
    code = pdf_find_same_charproc_aux(pdev, ppdfont, ppcp);
1026
98.5k
    pdev->find_resource_param = NULL;
1027
98.5k
    *ppdfont = data.pdfont;
1028
98.5k
    return code;
1029
98.5k
}
1030
1031
static bool
1032
pdf_is_charproc_defined(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, gs_char ch)
1033
9.24k
{
1034
9.24k
    pdf_char_proc_ownership_t *pcpo;
1035
1036
131k
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
1037
122k
        if (pcpo->char_code == ch)
1038
20
            return true;
1039
122k
    }
1040
9.22k
    return false;
1041
9.24k
}
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
98.6k
{
1048
98.6k
    pdf_font_resource_t *pdfont;
1049
98.6k
    double *real_widths;
1050
98.6k
    byte *glyph_usage;
1051
98.6k
    int char_cache_size, width_cache_size;
1052
98.6k
    pdf_encoding_element_t *pet;
1053
98.6k
    int code;
1054
1055
98.6k
    code = pdf_attached_font_resource(pdev, font, &pdfont,
1056
98.6k
                &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1057
98.6k
    if (code < 0)
1058
0
        return code;
1059
98.6k
    code = pdf_attach_charproc(pdev, pdfont, pcp, glyph, ch, gnstr);
1060
98.6k
    if (code < 0)
1061
0
        return code;
1062
98.6k
    if (ch >= char_cache_size || ch >= width_cache_size)
1063
0
        return_error(gs_error_unregistered); /* Must not happen. */
1064
98.6k
    pet = &pdfont->u.simple.Encoding[ch];
1065
98.6k
    pdfont->Widths[ch] = pcp->real_width.x;
1066
98.6k
    real_widths[ch * 2    ] = pcp->real_width.x;
1067
98.6k
    real_widths[ch * 2 + 1] = pcp->real_width.y;
1068
98.6k
    glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
1069
98.6k
    pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
1070
98.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
98.6k
    pet->glyph = glyph;
1075
98.6k
    pet->is_difference = true;
1076
98.6k
    if (pdfont->u.simple.LastChar < (int)ch)
1077
3.25k
        pdfont->u.simple.LastChar = (int)ch;
1078
98.6k
    if (pdfont->u.simple.FirstChar > (int)ch)
1079
2.06k
        pdfont->u.simple.FirstChar = (int)ch;
1080
98.6k
    return pdf_copy_string_to_encoding(pdev, (gs_const_string *)gnstr, pet);
1081
98.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
98.6k
{
1115
98.6k
    int code;
1116
98.6k
    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
98.6k
    pdf_char_proc_t *pcp = (pdf_char_proc_t *)pres;
1121
98.6k
    pdf_font_resource_t *pdfont;
1122
98.6k
    gs_char ch = output_char_code;
1123
98.6k
    bool checking_glyph_variation = false;
1124
1125
98.6k
    if (ch == GS_NO_CHAR)
1126
0
        return_error(gs_error_unregistered); /* Must not happen. */
1127
98.6k
    if (ch >= 256)
1128
0
        return_error(gs_error_unregistered); /* Must not happen. */
1129
98.6k
    if (pres == NULL)
1130
0
        return_error(gs_error_unregistered); /* Must not happen. */
1131
98.6k
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
1132
98.6k
    if (code < 0)
1133
0
        return code;
1134
98.6k
    if (pdfont != (pdf_font_resource_t *)pdev->font3)
1135
11
        return_error(gs_error_unregistered); /* Must not happen. */
1136
98.6k
    code = pdf_exit_substream(pdev);
1137
98.6k
    if (code < 0)
1138
0
        return code;
1139
98.6k
    if (!(pdfont->used[ch >> 3] & (0x80 >> (ch & 7))) ||
1140
98.6k
        !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) {
1141
        /* First appearence or not cached - check for duplicates. */
1142
98.5k
        pdf_font_resource_t *pdfont1 = pdfont;
1143
1144
98.5k
        checking_glyph_variation = true;
1145
        /* CAUTION : a possible font change. */
1146
98.5k
        code = pdf_find_same_charproc(pdev, &pdfont, cgp, &pcp, glyph, ch, font);
1147
98.5k
        if (code < 0)
1148
0
            return code;
1149
98.5k
        if (code != 0) {
1150
89.3k
            code = pdf_cancel_resource(pdev, pres, resourceCharProc);
1151
89.3k
            if (code < 0)
1152
0
                return code;
1153
89.3k
            pdf_forget_resource(pdev, pres, resourceCharProc);
1154
89.3k
            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
89.3k
            pdev->charproc_just_accumulated = true;
1163
89.3k
            return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
1164
89.3k
        }
1165
9.24k
        if (pdf_is_charproc_defined(pdev, pdfont, ch)) {
1166
            /* Encoding conflict after a font change. */
1167
20
            gs_font *base_font = font, *below;
1168
1169
20
            while ((below = base_font->base) != base_font &&
1170
20
                    base_font->procs.same_font(base_font, below, FONT_SAME_OUTLINES))
1171
0
                base_font = below;
1172
20
            code = pdf_make_font3_resource(pdev, base_font, &pdfont);
1173
20
            if (code < 0)
1174
0
                return code;
1175
20
            code = pdf_attach_font_resource(pdev, font, pdfont);
1176
20
            if (code < 0)
1177
0
                return code;
1178
20
        }
1179
9.24k
    }
1180
9.25k
    pdf_reserve_object_id(pdev, pres, 0);
1181
9.25k
    if (checking_glyph_variation)
1182
9.24k
        pdev->charproc_just_accumulated = true;
1183
9.25k
    return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
1184
98.6k
}
1185
1186
/* Add procsets to substream Resources. */
1187
int
1188
pdf_add_procsets(cos_dict_t *pcd, pdf_procset_t procsets)
1189
3.83k
{
1190
3.83k
    char str[5 + 7 + 7 + 7 + 5 + 2];
1191
3.83k
    cos_value_t v;
1192
1193
3.83k
    strcpy(str, "[/PDF");
1194
3.83k
    if (procsets & ImageB)
1195
0
        strcat(str, "/ImageB");
1196
3.83k
    if (procsets & ImageC)
1197
2.05k
        strcat(str, "/ImageC");
1198
3.83k
    if (procsets & ImageI)
1199
5
        strcat(str, "/ImageI");
1200
3.83k
    if (procsets & Text)
1201
18
        strcat(str, "/Text");
1202
3.83k
    strcat(str, "]");
1203
3.83k
    cos_string_value(&v, (byte *)str, strlen(str));
1204
3.83k
    return cos_dict_put_c_key(pcd, "/ProcSet", &v);
1205
3.83k
}
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.57M
{
1211
1.57M
    if (pcd != 0) {
1212
39.1k
        const cos_value_t *v = cos_dict_find(pcd, (const byte *)key, strlen(key));
1213
39.1k
        cos_dict_t *list;
1214
39.1k
        int code;
1215
39.1k
        char buf[10 + (sizeof(long) * 8 / 3 + 1)], buf1[sizeof(pres->rname) + 1];
1216
1217
39.1k
        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
39.1k
        gs_snprintf(buf, sizeof(buf), "%"PRId64" 0 R\n", pres->object->id);
1224
39.1k
        if (v != NULL) {
1225
32.0k
            if (v->value_type != COS_VALUE_OBJECT &&
1226
32.0k
                v->value_type != COS_VALUE_RESOURCE)
1227
0
                return_error(gs_error_unregistered); /* Must not happen. */
1228
32.0k
            list = (cos_dict_t *)v->contents.object;
1229
32.0k
            if (list->cos_procs != &cos_dict_procs)
1230
0
                return_error(gs_error_unregistered); /* Must not happen. */
1231
32.0k
        } else {
1232
7.10k
            list = cos_dict_alloc(pdev, "pdf_add_resource");
1233
7.10k
            if (list == NULL)
1234
0
                return_error(gs_error_VMerror);
1235
7.10k
            code = cos_dict_put_c_key_object((cos_dict_t *)pcd, key, (cos_object_t *)list);
1236
7.10k
            if (code < 0)
1237
0
                return code;
1238
7.10k
        }
1239
39.1k
        buf1[0] = '/';
1240
39.1k
        strcpy(buf1 + 1, pres->rname);
1241
39.1k
        return cos_dict_put_string(list, (const byte *)buf1, strlen(buf1),
1242
39.1k
                        (const byte *)buf, strlen(buf));
1243
39.1k
    }
1244
1.53M
    return 0;
1245
1.57M
}