Coverage Report

Created: 2026-07-24 07:44

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