Coverage Report

Created: 2026-02-14 07:09

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
206k
{
72
206k
    return pdf_resource_id((const pdf_resource_t *)pcp);
73
206k
}
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
83.5k
{
79
83.5k
    pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
80
83.5k
    pdf_font_resource_t *pdfont = pbfs->open_font; /* Type 3 */
81
83.5k
    int i, c = 0, code;
82
83.5k
    uint operation = pte->text.operation;
83
84
83.5k
    if (pbfs->bitmap_encoding_id == 0)
85
1.61k
        pbfs->bitmap_encoding_id = pdf_obj_ref(pdev);
86
83.5k
    if (pdfont == 0 || pdfont->u.simple.LastChar == 255 ||
87
81.8k
        !pbfs->use_open_font
88
83.5k
        ) {
89
        /* Start a new synthesized font. */
90
1.92k
        char *pc;
91
92
1.92k
        code = pdf_font_type3_alloc(pdev, &pdfont, pdf_write_contents_bitmap);
93
1.92k
        if (code < 0)
94
0
            return code;
95
1.92k
        pdfont->u.simple.s.type3.bitmap_font = true;
96
1.92k
        if (pbfs->open_font == 0)
97
1.61k
            pdfont->rname[0] = 0;
98
307
        else
99
307
            strcpy(pdfont->rname, pbfs->open_font->rname);
100
1.92k
        pdfont->u.simple.s.type3.FontBBox.p.x = 0;
101
1.92k
        pdfont->u.simple.s.type3.FontBBox.p.y = 0;
102
1.92k
        pdfont->u.simple.s.type3.FontBBox.q.x = 0;
103
1.92k
        pdfont->u.simple.s.type3.FontBBox.q.y = 0;
104
1.92k
        pdfont->mark_glyph = NULL;
105
1.92k
        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.92k
        for (pc = pdfont->rname; *pc == 'Z'; ++pc)
111
0
            *pc = '@';
112
1.92k
        if ((*pc)++ == 0)
113
1.61k
            *pc = 'A', pc[1] = 0;
114
1.92k
        pbfs->open_font = pdfont;
115
1.92k
        pbfs->use_open_font = true;
116
1.92k
        pdfont->u.simple.FirstChar = 255;
117
1.92k
    }
118
83.5k
    if ((operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) ||
119
83.5k
        (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR))) {
120
83.5k
        unsigned char p = *pte->text.data.bytes;
121
83.5k
        unsigned char index = p / 8, bit = 0x01 << (p % 8);
122
123
83.5k
        if (pdfont->used[index] & bit) {
124
5.65M
            for (i = 0;i < 256;i++) {
125
5.65M
                index = i / 8;
126
5.65M
                bit = 0x01 << (i % 8);
127
5.65M
                if (!(pdfont->used[index] & bit)) {
128
74.9k
                    c = i;
129
74.9k
                    break;
130
74.9k
                }
131
5.65M
            }
132
74.9k
        } else
133
8.61k
            c = p;
134
83.5k
        pdfont->used[index] |= bit;
135
83.5k
        if (c > pdfont->u.simple.LastChar)
136
54.5k
            pdfont->u.simple.LastChar = c;
137
138
83.5k
    } else {
139
0
        unsigned char index, bit;
140
0
        c = ++(pdfont->u.simple.LastChar);
141
0
        index = c / 8;
142
0
        bit = 0x01 << (c % 8);
143
0
        pdfont->used[index] |= bit;
144
0
    }
145
83.5k
    if (c < pdfont->u.simple.FirstChar)
146
3.01k
        pdfont->u.simple.FirstChar = c;
147
148
83.5k
    pdfont->Widths[c] = psdf_round(pdev->char_width.x, 100, 10); /* See
149
                        pdf_write_Widths about rounding. We need to provide
150
                        a compatible data for Tj. */
151
83.5k
    if (c > pbfs->max_embedded_code)
152
45.9k
        pbfs->max_embedded_code = c;
153
154
83.5k
    return c;
155
83.5k
}
156
157
/* Write the contents of a Type 3 bitmap or vector font resource. */
158
int
159
pdf_write_contents_bitmap(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
160
3.18k
{
161
3.18k
    stream *s = pdev->strm;
162
3.18k
    const pdf_char_proc_ownership_t *pcpo;
163
3.18k
    int64_t diff_id = 0;
164
3.18k
    int code;
165
166
3.18k
    if (pdfont->u.simple.s.type3.bitmap_font)
167
1.92k
        diff_id = pdev->text->bitmap_fonts->bitmap_encoding_id;
168
1.26k
    else {
169
        /* See comment in pdf_write_encoding. */
170
1.26k
        diff_id = pdf_obj_ref(pdev);
171
1.26k
    }
172
3.18k
    code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
173
3.18k
    if (code < 0)
174
0
        return code;
175
3.18k
    stream_puts(s, "/CharProcs <<");
176
    /* Write real characters. */
177
106k
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo;
178
103k
         pcpo = pcpo->char_next
179
103k
         ) {
180
103k
        if (pdfont->u.simple.s.type3.bitmap_font)
181
83.5k
            pprinti64d2(s, "/a%"PRId64" %"PRId64" 0 R\n", pcpo->char_code,
182
83.5k
                      pdf_char_proc_id(pcpo->char_proc));
183
19.8k
        else if (!pcpo-> duplicate_char_name) {
184
19.7k
            pdf_put_name(pdev, pcpo->char_name.data, pcpo->char_name.size);
185
19.7k
            pprinti64d1(s, " %"PRId64" 0 R\n", pdf_char_proc_id(pcpo->char_proc));
186
19.7k
        }
187
103k
        pdf_record_usage_by_parent(pdev, pdf_char_proc_id(pcpo->char_proc), pdfont->object->id);
188
103k
    }
189
3.18k
    stream_puts(s, ">>");
190
3.18k
    pprintg6(s, "/FontMatrix[%g %g %g %g %g %g]",
191
3.18k
            (float)pdfont->u.simple.s.type3.FontMatrix.xx,
192
3.18k
            (float)pdfont->u.simple.s.type3.FontMatrix.xy,
193
3.18k
            (float)pdfont->u.simple.s.type3.FontMatrix.yx,
194
3.18k
            (float)pdfont->u.simple.s.type3.FontMatrix.yy,
195
3.18k
            (float)pdfont->u.simple.s.type3.FontMatrix.tx,
196
3.18k
            (float)pdfont->u.simple.s.type3.FontMatrix.ty);
197
3.18k
    code = pdf_finish_write_contents_type3(pdev, pdfont);
198
3.18k
    if (code < 0)
199
0
        return code;
200
3.18k
    if (!pdfont->u.simple.s.type3.bitmap_font && diff_id > 0) {
201
1.26k
        code = pdf_write_encoding(pdev, pdfont, diff_id, 0);
202
1.26k
        if (code < 0)
203
0
            return code;
204
1.26k
    }
205
3.18k
    return 0;
206
3.18k
}
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
45.4k
{
216
45.4k
    pdf_bitmap_fonts_t *pbfs =
217
45.4k
        gs_alloc_struct(mem, pdf_bitmap_fonts_t, &st_pdf_bitmap_fonts,
218
45.4k
                        "pdf_bitmap_fonts_alloc");
219
220
45.4k
    if (pbfs == 0)
221
0
        return 0;
222
45.4k
    memset(pbfs, 0, sizeof(*pbfs));
223
45.4k
    pbfs->max_embedded_code = -1;
224
45.4k
    return pbfs;
225
45.4k
}
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
58.4k
{
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
58.4k
    if (pdev->CompatibilityLevel <= 1.2)
243
32.4k
        pdev->text->bitmap_fonts->use_open_font = false;
244
58.4k
}
245
246
int
247
pdf_charproc_y_offset(pdf_char_proc_t *pcp)
248
827k
{
249
827k
    return pcp->y_offset;
250
827k
}
251
252
int
253
pdf_charproc_x_offset(pdf_char_proc_t *pcp)
254
827k
{
255
827k
    return pcp->x_offset;
256
827k
}
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
209k
{
263
209k
    pdf_char_proc_ownership_t *pcpo;
264
209k
    bool duplicate_char_name = false;
265
266
9.75M
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
267
9.64M
        if (pcpo->glyph == glyph && pcpo->char_code == char_code)
268
100k
            return 0;
269
9.64M
    }
270
109k
    if (!pdfont->u.simple.s.type3.bitmap_font) {
271
935k
        for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
272
910k
            if (!bytes_compare(pcpo->char_name.data, pcpo->char_name.size, gnstr->data, gnstr->size)) {
273
50
                duplicate_char_name = true;
274
50
                break;
275
50
            }
276
910k
        }
277
25.6k
    }
278
109k
    pcpo = gs_alloc_struct(pdev->pdf_memory,
279
109k
            pdf_char_proc_ownership_t, &st_pdf_char_proc_ownership, "pdf_attach_charproc");
280
281
109k
    if (pcpo == NULL)
282
0
        return_error(gs_error_VMerror);
283
109k
    pcpo->font = pdfont;
284
109k
    pcpo->char_next = pdfont->u.simple.s.type3.char_procs;
285
109k
    pdfont->u.simple.s.type3.char_procs = pcpo;
286
109k
    pcpo->char_proc = pcp;
287
109k
    pcpo->font_next = pcp->owner_fonts;
288
109k
    pcp->owner_fonts = pcpo;
289
109k
    pcpo->char_code = char_code;
290
109k
    pcpo->glyph = glyph;
291
109k
    if (gnstr == NULL) {
292
83.5k
        pcpo->char_name.data = 0;
293
83.5k
        pcpo->char_name.size = 0;
294
83.5k
    } else {
295
25.6k
        if (gnstr->size > 0) {
296
25.6k
            pcpo->char_name.data = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, gnstr->size, "storage for charproc name");
297
25.6k
            if (pcpo->char_name.data == NULL)
298
0
                return_error(gs_error_VMerror);
299
25.6k
            memcpy(pcpo->char_name.data, gnstr->data, gnstr->size);
300
25.6k
        }
301
25.6k
        pcpo->char_name.size = gnstr->size;
302
25.6k
    }
303
109k
    pcpo->duplicate_char_name = duplicate_char_name;
304
109k
    return 0;
305
109k
}
306
307
int
308
pdf_free_charproc_ownership(gx_device_pdf * pdev, pdf_resource_t *pres)
309
3.26k
{
310
3.26k
    pdf_char_proc_ownership_t *next, *pcpo = (pdf_char_proc_ownership_t *)pres;
311
312
112k
    while (pcpo) {
313
109k
        next = pcpo->char_next;
314
109k
        if(pcpo->char_name.size != 0 && pcpo->char_name.data) {
315
25.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
25.6k
            pcpo->char_name.data = (byte *)0L;
319
25.6k
            pcpo->char_name.size = 0;
320
25.6k
        }
321
109k
        gs_free_object(pdev->pdf_memory, pcpo, "Free CharProc");
322
109k
        pcpo = next;
323
109k
    }
324
3.26k
    return 0;
325
3.26k
}
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
83.5k
{
333
83.5k
    gs_char char_code = 0;
334
83.5k
    pdf_bitmap_fonts_t *const pbfs = pdev->text->bitmap_fonts;
335
83.5k
    pdf_font_resource_t *font;
336
83.5k
    pdf_resource_t *pres;
337
83.5k
    pdf_char_proc_t *pcp;
338
83.5k
    int code;
339
    /* This code added to store PCL bitmap glyphs in type 3 fonts where possible */
340
83.5k
    gs_glyph glyph = GS_NO_GLYPH;
341
83.5k
    gs_const_string str2, *str = NULL;
342
83.5k
    gs_show_enum *show_enum = (gs_show_enum *)pdev->pte;
343
83.5k
    pdf_encoding_element_t *pet = 0;
344
    /* Since this is for text searching, its only useful if the character code
345
     * lies in an ASCII range, so we only handle some kinds of text layout.
346
     */
347
83.5k
    int allowed_op = (show_enum->text.operation &
348
83.5k
        (TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR));
349
350
    /* Check to see the current font is a type 3. We can get here if pdfwrite decides
351
     * it can't handle a font type, and renders to a bitmap instead. If that's the
352
     * case then we can't add the bitmap to the existing font (its not a type 3 font)
353
     * and must fall back to holding it in our fallback type 3 font 'collection'.
354
     */
355
    /* Because the bitmaps are stored directly in the cache they already have any
356
     * effects caused by non-identity FontMatrix entries applied. So if the type 3
357
     * font we created has a non-identity FontMatrix we can't use it and must
358
     * go back to collecting the bitmap into our fallback font.
359
     */
360
83.5k
    if ((show_enum->current_font->FontType == ft_user_defined ||
361
83.5k
        show_enum->current_font->FontType == ft_PDF_user_defined ||
362
83.5k
        show_enum->current_font->FontType == ft_PCL_user_defined ||
363
83.5k
        show_enum->current_font->FontType == ft_MicroType ||
364
83.5k
        show_enum->current_font->FontType == ft_GL2_stick_user_defined ||
365
83.5k
        show_enum->current_font->FontType == ft_GL2_531) && allowed_op &&
366
0
        show_enum->current_font->FontMatrix.xx == 1 && show_enum->current_font->FontMatrix.xy == 0 &&
367
0
        show_enum->current_font->FontMatrix.yx == 0 && show_enum->current_font->FontMatrix.yy == 1) {
368
0
        pdf_char_proc_ownership_t *pcpo;
369
370
0
        gs_font_base *base = (gs_font_base *)show_enum->current_font;
371
0
        code = pdf_attached_font_resource(pdev, show_enum->current_font, &font, NULL, NULL, NULL, NULL);
372
0
        if (code < 0)
373
0
            return code;
374
0
        if (font == NULL)
375
0
            return_error(gs_error_invalidfont);
376
377
        /* The text processing will have run past the glyph, so we need to 'back up'
378
         * by one and get it again in order to get the character code and glyph, and update
379
         * the pointer correctly.
380
         */
381
0
        show_enum->index--;
382
0
        code = gs_default_next_char_glyph((gs_text_enum_t *)show_enum, (gs_char *)&char_code, &glyph);
383
0
        if (code < 0)
384
0
            return code;
385
386
        /* If the returned character code is outside the possible Encoding for
387
         * a type 3 font, then set pet to NULL, this means we will fall back to
388
         * the 'collection' font, as pet is checked below.
389
         */
390
0
        if ((int)char_code >= 0 && (int)char_code <= 255) {
391
0
            pet = &font->u.simple.Encoding[char_code];
392
0
            if (pet) {
393
                /* Check to see if we *already* have this glyph in this font. If
394
                 * we do then we can't add it to this font. Setting pet to 0
395
                 * falls back to the collection method.
396
                 */
397
0
                for (pcpo = font->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
398
0
                    if (pcpo->glyph == pet->glyph && pcpo->char_code == char_code) {
399
0
                        pet = 0x00;
400
0
                        break;
401
0
                    }
402
0
                }
403
0
            }
404
0
        }
405
0
        else
406
0
            pet = 0x00;
407
408
        /* We need a glyph name for the type 3 font's Encoding, if we haven't got one
409
         * then we need to give up, something about the font or text is not acceptable
410
         * (see various comments above).
411
         */
412
0
        if (pet && pet->glyph != GS_NO_GLYPH && !(pet->size == 7 &&
413
0
            !strncmp((const char *)pet->data, ".notdef", 7))) {
414
0
            if (char_code < font->u.simple.FirstChar)
415
0
                font->u.simple.FirstChar = char_code;
416
0
            if ((int)char_code > font->u.simple.LastChar)
417
0
                font->u.simple.LastChar = char_code;
418
0
            base->FontBBox.q.x = max(base->FontBBox.q.x, w);
419
0
            base->FontBBox.q.y = max(base->FontBBox.q.y, y_offset + h);
420
0
            str2.data = pet->data;
421
0
            str2.size = pet->size;
422
0
            str = &str2;
423
0
            glyph = pet->glyph;
424
            /* This is to work around a weird Acrobat bug. If the Encoding of a type 3
425
             * (possibly other types) is simply a standard encoding (eg WinAnsiEncoding)
426
             * then Acrobat 4 & 8 just ignore the glyphs altogether. This forces us to write
427
             * all the used glyphs as /Differencess, and that makes it work <sigh>
428
             */
429
0
            pet->is_difference = 1;
430
0
            font->Widths[char_code] = psdf_round(pdev->char_width.x, 100, 10); /* See
431
                        pdf_write_Widths about rounding. We need to provide
432
                        a compatible data for Tj. */
433
0
        } else {
434
0
            char_code = assign_char_code(pdev, pdev->pte);
435
0
            font = pbfs->open_font; /* Type 3 */
436
0
        }
437
83.5k
    } else {
438
83.5k
        char_code = assign_char_code(pdev, pdev->pte);
439
83.5k
        font = pbfs->open_font; /* Type 3 */
440
83.5k
    }
441
442
83.5k
    code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
443
83.5k
    if (code < 0)
444
0
        return code;
445
83.5k
    pcp = (pdf_char_proc_t *) pres;
446
83.5k
    code = pdf_attach_charproc(pdev, font, pcp, glyph, char_code, str);
447
83.5k
    if (code < 0)
448
0
        return code;
449
83.5k
    pres->object->written = true;
450
83.5k
    {
451
83.5k
        stream *s = pdev->strm;
452
453
        /*
454
         * The resource file is positionable, so rather than use an
455
         * object reference for the length, we'll go back and fill it in
456
         * at the end of the definition.  Take 1M as the longest
457
         * definition we can handle.  (This used to be 10K, but there was
458
         * a real file that exceeded this limit.)
459
         */
460
83.5k
        stream_puts(s, "<</Length       >>stream\n");
461
83.5k
        ppos->start_pos = stell(s);
462
83.5k
    }
463
83.5k
    code = pdf_begin_encrypt(pdev, &pdev->strm, pres->object->id);
464
83.5k
    if (code < 0)
465
0
        return code;
466
83.5k
    pcp->y_offset = y_offset;
467
83.5k
    pcp->x_offset = x_offset;
468
83.5k
    font->u.simple.s.type3.FontBBox.q.x =
469
83.5k
        max(font->u.simple.s.type3.FontBBox.q.x, w);
470
83.5k
    font->u.simple.s.type3.FontBBox.q.y =
471
83.5k
        max(font->u.simple.s.type3.FontBBox.q.y, y_offset + h);
472
83.5k
    font->u.simple.s.type3.max_y_offset =
473
83.5k
        max(font->u.simple.s.type3.max_y_offset, h + (h >> 2));
474
83.5k
    pcp->real_width.x = w;
475
83.5k
    pcp->real_width.y = y_offset + h;
476
83.5k
    *ppcp = pcp;
477
83.5k
    return 0;
478
83.5k
}
479
480
/* End a CharProc. */
481
int
482
pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos)
483
83.5k
{
484
83.5k
    stream *s;
485
83.5k
    gs_offset_t start_pos, end_pos, length;
486
487
83.5k
    if (pdf_end_encrypt(pdev))
488
0
        s_close_filters(&pdev->strm, pdev->strm->strm);
489
490
83.5k
    s = pdev->strm;
491
83.5k
    start_pos = ppos->start_pos;
492
83.5k
    end_pos = stell(s);
493
83.5k
    length = end_pos - start_pos;
494
83.5k
    if (length > 999999)
495
0
        return_error(gs_error_limitcheck);
496
83.5k
    sseek(s, start_pos - 15);
497
83.5k
    pprintd1(s, "%d", length);
498
83.5k
    sseek(s, end_pos);
499
83.5k
    if (pdev->PDFA != 0)
500
0
        stream_puts(s, "\n");
501
83.5k
    stream_puts(s, "endstream\n");
502
83.5k
    pdf_end_separate(pdev, resourceCharProc);
503
83.5k
    return 0;
504
83.5k
}
505
506
/* Mark glyph names for garbager. */
507
void
508
pdf_mark_glyph_names(const pdf_font_resource_t *pdfont, const gs_memory_t *memory)
509
36.6k
{
510
36.6k
    if (pdfont->mark_glyph == NULL) {
511
        /* Synthesised bitmap fonts pass here. */
512
33.9k
        return;
513
33.9k
    }
514
2.70k
    if (pdfont->u.simple.Encoding != NULL) {
515
2.70k
         int i;
516
517
694k
         for (i = 0; i < 256; i++)
518
691k
             if (pdfont->u.simple.Encoding[i].glyph != GS_NO_GLYPH)
519
97.3k
                pdfont->mark_glyph(memory, pdfont->u.simple.Encoding[i].glyph, pdfont->mark_glyph_data);
520
2.70k
     }
521
2.70k
    if (pdfont->FontType == ft_user_defined ||
522
2.12k
        pdfont->FontType == ft_PDF_user_defined ||
523
2.12k
        pdfont->FontType == ft_PCL_user_defined ||
524
2.12k
        pdfont->FontType == ft_MicroType ||
525
2.12k
        pdfont->FontType == ft_GL2_stick_user_defined ||
526
2.12k
        pdfont->FontType == ft_GL2_531) {
527
573
        const pdf_char_proc_ownership_t *pcpo = pdfont->u.simple.s.type3.char_procs;
528
529
13.4k
        for (; pcpo != NULL; pcpo = pcpo->font_next)
530
12.9k
            pdfont->mark_glyph(memory, pcpo->glyph, pdfont->mark_glyph_data);
531
573
    }
532
2.70k
}
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
911k
{
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
911k
    const pdf_char_proc_ownership_t * pcpo = pcp->owner_fonts;
543
911k
    pdf_font_resource_t *pdfont = pcpo->font;
544
911k
    byte ch = pcpo->char_code;
545
911k
    pdf_text_state_values_t values;
546
547
911k
    values.character_spacing = 0;
548
911k
    values.pdfont = pdfont;
549
911k
    values.size = 1;
550
911k
    values.matrix = *pimat;
551
911k
    values.render_mode = pdev->pte->pgs->text_rendering_mode;
552
911k
    values.word_spacing = 0;
553
911k
    pdf_set_text_state_values(pdev, &values);
554
911k
    pdf_bitmap_char_update_bbox(pdev, pcp->x_offset, pcp->y_offset, pcp->real_width.x, pcp->real_width.y);
555
911k
    pdf_append_chars(pdev, &ch, 1, pdfont->Widths[ch] * pimat->xx, 0.0, false);
556
911k
    return 0;
557
911k
}
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
45.4k
{
565
45.4k
    pdf_bitmap_fonts_t *pbfs;
566
567
45.4k
    if (pdev->text == NULL || pdev->text->bitmap_fonts == NULL)
568
0
        return 0;
569
570
45.4k
    pbfs = pdev->text->bitmap_fonts;
571
572
45.4k
    if (pbfs->bitmap_encoding_id) {
573
1.61k
        stream *s;
574
1.61k
        int i;
575
576
1.61k
        pdf_open_separate(pdev, pbfs->bitmap_encoding_id, resourceEncoding);
577
1.61k
        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.61k
        stream_puts(s, "<</Type/Encoding/Differences[0");
586
112k
        for (i = 0; i <= pbfs->max_embedded_code; ++i) {
587
110k
            if (!(i & 15))
588
7.74k
                stream_puts(s, "\n");
589
110k
            pprintd1(s, "/a%d", i);
590
110k
        }
591
1.61k
        stream_puts(s, "\n] >>\n");
592
1.61k
        pdf_end_separate(pdev, resourceEncoding);
593
1.61k
        pbfs->bitmap_encoding_id = 0;
594
1.61k
    }
595
45.4k
    return 0;
596
45.4k
}
597
598
/*
599
 * Start charproc accumulation for a Type 3 font.
600
 */
601
int
602
pdf_start_charproc_accum(gx_device_pdf *pdev)
603
125k
{
604
125k
    pdf_char_proc_t *pcp;
605
125k
    pdf_resource_t *pres;
606
125k
    int id = gs_next_ids(pdev->memory, 1);
607
125k
    int code = pdf_enter_substream(pdev, resourceCharProc, id,
608
125k
                                   &pres, false, pdev->CompressFonts);
609
610
125k
    if (code < 0)
611
1
       return code;
612
125k
    pres->rid = id;
613
125k
    pcp = (pdf_char_proc_t *)pres;
614
125k
    pcp->owner_fonts = NULL;
615
125k
    return 0;
616
125k
}
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
109k
{
625
109k
    pdf_font_resource_t *pdfont;
626
109k
    pdf_resource_t *pres = pdev->accumulating_substream_resource;
627
109k
    pdf_char_proc_t *pcp;
628
109k
    int code;
629
630
109k
    if (pres == NULL)
631
0
        return_error(gs_error_undefined);
632
109k
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
633
109k
    if (code < 0)
634
0
        return code;
635
109k
    pcp = (pdf_char_proc_t *)pres;
636
109k
    pcp->owner_fonts = NULL;
637
109k
    pcp->real_width.x = pw[font->WMode && narg > 6 ? 6 : 0];
638
109k
    pcp->real_width.y = pw[font->WMode && narg > 6 ? 7 : 1];
639
109k
    pcp->v.x = (narg > 8 ? pw[8] : 0);
640
109k
    pcp->v.y = (narg > 8 ? pw[9] : 0);
641
109k
    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
99.3k
        pdev->skip_colors = false;
647
99.3k
        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
99.3k
        if (font->FontType == ft_PCL_user_defined || font->FontType == ft_GL2_stick_user_defined
653
99.3k
            || font->FontType == ft_GL2_531 || font->FontType == ft_MicroType)
654
0
            pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
655
99.3k
    } else {
656
10.2k
        double d;
657
10.2k
        pdev->skip_colors = true;
658
10.2k
        if (pw[4] < pw[2]) {
659
23
            d = pw[2];
660
23
            pw[2] = pw[4];
661
23
            pw[4] = d;
662
23
        }
663
10.2k
        if (pw[5] < pw[3]) {
664
39
            d = pw[5];
665
39
            pw[5] = pw[3];
666
39
            pw[3] = d;
667
39
        }
668
10.2k
        pprintg6(pdev->strm, "%g %g %g %g %g %g d1\n",
669
10.2k
            (float)pw[0], (float)0.0, (float)pw[2],
670
10.2k
            (float)pw[3], (float)pw[4], (float)pw[5]);
671
10.2k
        pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
672
10.2k
    }
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
109k
    if (scale_100) {
680
109k
    code = stream_puts(pdev->strm, "0.01 0 0 0.01 0 0 cm\n");
681
109k
    if (code < 0)
682
0
        return code;
683
109k
    }
684
109k
    return 0;
685
109k
}
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
249k
{
695
249k
    int code;
696
249k
    pdf_resource_t *pres;
697
249k
    stream *s, *save_strm = pdev->strm;
698
249k
    pdf_data_writer_t writer;
699
249k
    static const pdf_filter_names_t fnames = {
700
249k
        PDF_FILTER_NAMES
701
249k
    };
702
703
249k
    pdev->streams.save_strm = pdev->strm;
704
705
249k
    if (rtype >= NUM_RESOURCE_TYPES)
706
70.1k
        rtype = resourceOther;
707
249k
    code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id),
708
249k
                pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1);
709
249k
    if (code < 0)
710
0
        return code;
711
249k
    cos_become(pres->object, cos_type_stream);
712
249k
    s = cos_write_stream_alloc((cos_stream_t *)pres->object, pdev, "pdf_enter_substream");
713
249k
    if (s == 0)
714
0
        return_error(gs_error_VMerror);
715
249k
    pdev->strm = s;
716
249k
    code = pdf_append_data_stream_filters(pdev, &writer,
717
249k
                             options | DATA_STREAM_NOLENGTH, pres->object->id);
718
249k
    if (code < 0) {
719
0
        pdev->strm = save_strm;
720
0
        return code;
721
0
    }
722
249k
    code = pdf_put_filters((cos_dict_t *)pres->object, pdev, writer.binary.strm, &fnames);
723
249k
    if (code < 0) {
724
0
        pdev->strm = save_strm;
725
0
        return code;
726
0
    }
727
249k
    pdev->strm = writer.binary.strm;
728
249k
    *ppres = pres;
729
249k
    return 0;
730
249k
}
731
732
/*
733
 * Close a stream object in the temporary file.
734
 */
735
int
736
pdf_close_aside(gx_device_pdf *pdev)
737
249k
{
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
249k
    stream *s = pdev->strm;
742
249k
    cos_stream_t *pcs = cos_stream_from_pipeline(s);
743
249k
    int status = s_close_filters(&s, NULL);
744
745
249k
    pdev->strm = pdev->streams.save_strm;
746
249k
    if (status < 0)
747
0
         return(gs_note_error(gs_error_ioerror));
748
749
249k
    if (!pcs)
750
0
        return gs_note_error(gs_error_ioerror);
751
752
249k
    pcs->is_open = false;
753
249k
    return 0;
754
249k
}
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
178k
{
763
178k
    int sbstack_ptr = pdev->sbstack_depth;
764
178k
    pdf_resource_t *pres;
765
178k
    stream *save_strm = pdev->strm;
766
178k
    int code;
767
768
178k
    if (pdev->sbstack_depth >= pdev->sbstack_size)
769
1
        return_error(gs_error_unregistered); /* Must not happen. */
770
178k
    if (pdev->sbstack[sbstack_ptr].text_state == 0) {
771
178k
        pdev->sbstack[sbstack_ptr].text_state = pdf_text_state_alloc(pdev->pdf_memory);
772
178k
        if (pdev->sbstack[sbstack_ptr].text_state == 0)
773
0
            return_error(gs_error_VMerror);
774
178k
    }
775
178k
    code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id,
776
178k
                    (compress ? DATA_STREAM_COMPRESS : 0));
777
178k
    if (code < 0)
778
0
        return code;
779
178k
    code = pdf_save_viewer_state(pdev, NULL);
780
178k
    if (code < 0) {
781
0
        pdev->strm = save_strm;
782
0
        return code;
783
0
    }
784
178k
    pdev->sbstack[sbstack_ptr].context = pdev->context;
785
178k
    pdf_text_state_copy(pdev->sbstack[sbstack_ptr].text_state, pdev->text->text_state);
786
178k
    pdf_set_text_state_default(pdev->text->text_state);
787
178k
    pdev->sbstack[sbstack_ptr].clip_path = pdev->clip_path;
788
178k
    pdev->clip_path = 0;
789
178k
    pdev->sbstack[sbstack_ptr].clip_path_id = pdev->clip_path_id;
790
178k
    pdev->clip_path_id = pdev->no_clip_path_id;
791
178k
    pdev->sbstack[sbstack_ptr].vgstack_bottom = pdev->vgstack_bottom;
792
178k
    pdev->vgstack_bottom = pdev->vgstack_depth;
793
178k
    pdev->sbstack[sbstack_ptr].strm = save_strm;
794
178k
    pdev->sbstack[sbstack_ptr].procsets = pdev->procsets;
795
178k
    pdev->sbstack[sbstack_ptr].substream_Resources = pdev->substream_Resources;
796
178k
    pdev->sbstack[sbstack_ptr].skip_colors = pdev->skip_colors;
797
178k
    pdev->sbstack[sbstack_ptr].font3 = pdev->font3;
798
178k
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = pdev->accumulating_substream_resource;
799
178k
    pdev->sbstack[sbstack_ptr].charproc_just_accumulated = pdev->charproc_just_accumulated;
800
178k
    pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object;
801
178k
    pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict;
802
178k
    pdev->sbstack[sbstack_ptr].objname = pdev->objname;
803
178k
    pdev->sbstack[sbstack_ptr].last_charpath_op = pdev->last_charpath_op;
804
178k
    pdev->skip_colors = false;
805
178k
    pdev->charproc_just_accumulated = false;
806
178k
    pdev->pres_soft_mask_dict = NULL;
807
178k
    pdev->objname.data = NULL;
808
178k
    pdev->objname.size = 0;
809
    /* Do not reset pdev->accumulating_a_global_object - it inherits. */
810
178k
    pdev->sbstack_depth++;
811
178k
    pdev->procsets = 0;
812
178k
    pdev->font3 = 0;
813
178k
    pdev->context = PDF_IN_STREAM;
814
178k
    pdev->accumulating_substream_resource = pres;
815
178k
    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
178k
    if (rtype != resourceXObject)
820
162k
        pdf_reset_graphics(pdev);
821
16.4k
    else {
822
16.4k
        if (pdev->vg_initial_set)
823
16.4k
            pdev->state.blend_mode = pdev->vg_initial.blend_mode;
824
16.4k
    }
825
178k
    *ppres = pres;
826
178k
    return 0;
827
178k
}
828
829
/*
830
 * Exit the substream accumulation mode.
831
 */
832
int
833
pdf_exit_substream(gx_device_pdf *pdev)
834
178k
{
835
178k
    int code, code1;
836
178k
    int sbstack_ptr;
837
838
178k
    if (pdev->sbstack_depth <= 0)
839
2
        return_error(gs_error_unregistered); /* Must not happen. */
840
178k
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
841
178k
    sbstack_ptr = pdev->sbstack_depth - 1;
842
194k
    while (pdev->vgstack_depth > pdev->vgstack_bottom) {
843
15.7k
        code1 = pdf_restore_viewer_state(pdev, pdev->strm);
844
15.7k
        if (code >= 0)
845
15.7k
            code = code1;
846
15.7k
    }
847
178k
    if (pdev->clip_path != 0)
848
0
        gx_path_free(pdev->clip_path, "pdf_end_charproc_accum");
849
178k
    code1 = pdf_close_aside(pdev);
850
178k
    if (code1 < 0 && code >= 0)
851
0
        code = code1;
852
178k
    pdev->context = pdev->sbstack[sbstack_ptr].context;
853
178k
    pdf_text_state_copy(pdev->text->text_state, pdev->sbstack[sbstack_ptr].text_state);
854
178k
    gs_free_object(pdev->pdf_memory, pdev->sbstack[sbstack_ptr].text_state, "free text state for stream");
855
178k
    pdev->sbstack[sbstack_ptr].text_state = 0;
856
178k
    pdev->clip_path = pdev->sbstack[sbstack_ptr].clip_path;
857
178k
    pdev->sbstack[sbstack_ptr].clip_path = 0;
858
178k
    pdev->clip_path_id = pdev->sbstack[sbstack_ptr].clip_path_id;
859
178k
    pdev->vgstack_bottom = pdev->sbstack[sbstack_ptr].vgstack_bottom;
860
178k
    pdev->strm = pdev->sbstack[sbstack_ptr].strm;
861
178k
    pdev->sbstack[sbstack_ptr].strm = 0;
862
178k
    pdev->procsets = pdev->sbstack[sbstack_ptr].procsets;
863
178k
    pdev->substream_Resources = pdev->sbstack[sbstack_ptr].substream_Resources;
864
178k
    pdev->sbstack[sbstack_ptr].substream_Resources = 0;
865
178k
    pdev->skip_colors = pdev->sbstack[sbstack_ptr].skip_colors;
866
178k
    pdev->font3 = pdev->sbstack[sbstack_ptr].font3;
867
178k
    pdev->sbstack[sbstack_ptr].font3 = 0;
868
178k
    pdev->accumulating_substream_resource = pdev->sbstack[sbstack_ptr].accumulating_substream_resource;
869
178k
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = 0;
870
178k
    pdev->charproc_just_accumulated = pdev->sbstack[sbstack_ptr].charproc_just_accumulated;
871
178k
    pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object;
872
178k
    pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict;
873
178k
    pdev->objname = pdev->sbstack[sbstack_ptr].objname;
874
178k
    pdev->last_charpath_op = pdev->sbstack[sbstack_ptr].last_charpath_op;
875
178k
    pdev->sbstack_depth = sbstack_ptr;
876
178k
    code1 = pdf_restore_viewer_state(pdev, NULL);
877
178k
    if (code1 < 0 && code >= 0)
878
0
        code = code1;
879
178k
    return code;
880
178k
}
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
306k
{
885
306k
    if (pcp0->real_width.x != pcp1->real_width.x)
886
170k
        return false;
887
135k
    if (pcp0->real_width.y != pcp1->real_width.y)
888
0
        return false;
889
135k
    if (pcp0->v.x != pcp1->v.x)
890
0
        return false;
891
135k
    if (pcp0->v.y != pcp1->v.y)
892
0
        return false;
893
135k
    return true;
894
135k
}
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
203
{
907
203
    pdf_char_proc_ownership_t *pcpo;
908
909
1.47k
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
910
1.27k
        if (pcpo->char_code == char_code) {
911
2
            return true;
912
2
        }
913
1.27k
    }
914
201
    return false;
915
203
}
916
917
static int
918
pdf_is_charproc_compatible(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
919
203
{
920
203
    charproc_compatibility_data_t *data = (charproc_compatibility_data_t *)pdev->find_resource_param;
921
203
    pdf_char_proc_t *pcp0 = (pdf_char_proc_t *)pres0;
922
203
    pdf_char_proc_t *pcp1 = (pdf_char_proc_t *)pres1;
923
203
    pdf_font_resource_t *pdfont = data->pdfont;
924
203
    pdf_char_proc_ownership_t *pcpo;
925
203
    pdf_font_cache_elem_t **e;
926
203
    bool can_add_to_current_font = false, computed_can_add_to_current_font = false;
927
928
    /* Does it have same attributes ? */
929
203
    if (!pdf_is_same_charproc_attrs1(pdev, pcp0, pcp1))
930
0
        return 0;
931
    /* Is it from same font ? */
932
2.23k
    for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
933
2.03k
        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.03k
    }
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
203
    e = pdf_locate_font_cache_elem(pdev, data->font);
951
203
    if (e != NULL) {
952
2.23k
        for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
953
2.03k
            if (pcpo->char_code != data->char_code || pcpo->glyph != data->glyph)
954
1.93k
                continue; /* Need same Encoding to generate a proper ToUnicode. */
955
100
            if (pdfont->u.simple.s.type3.bitmap_font != pcpo->font->u.simple.s.type3.bitmap_font)
956
0
                continue;
957
100
            if (gs_matrix_compare(&pdfont->u.simple.s.type3.FontMatrix, &pcpo->font->u.simple.s.type3.FontMatrix))
958
20
                continue;
959
80
            if (data->cgp != NULL) {
960
77
                if (!pdf_check_encoding_compatibility(pcpo->font, data->cgp->s, data->cgp->num_all_chars))
961
0
                    continue;
962
77
            }
963
80
            if ((*e)->pdfont != pcpo->font)
964
80
                continue;
965
0
            data->pdfont = pcpo->font; /* Switch to the other font. */
966
0
            return 1;
967
80
        }
968
203
    }
969
    /* Check whether it can be added into the current font. */
970
203
    if (!computed_can_add_to_current_font)
971
203
        can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
972
203
    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
201
    return 1;
978
203
}
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
125k
{
984
125k
    pdf_char_proc_ownership_t *pcpo;
985
125k
    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
317k
    for (pcpo = (*ppdfont)->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
992
306k
        pdf_char_proc_t *pcp = pcpo->char_proc;
993
994
306k
        if (*ppcp != pcp && pdf_is_same_charproc_attrs1(pdev, *ppcp, pcp)) {
995
135k
            cos_object_t *pco0 = pcp->object;
996
135k
            cos_object_t *pco1 = (*ppcp)->object;
997
998
135k
            code = pco0->cos_procs->equal(pco0, pco1, pdev);
999
135k
            if (code < 0) {
1000
0
                return code;
1001
0
            }
1002
135k
            if (code) {
1003
114k
                *ppcp = pcp;
1004
114k
                return 1;
1005
114k
            }
1006
135k
        }
1007
306k
    }
1008
10.8k
    return pdf_find_same_resource(pdev, resourceCharProc, (pdf_resource_t **)ppcp, pdf_is_charproc_compatible);
1009
125k
}
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
125k
{
1016
125k
    charproc_compatibility_data_t data;
1017
125k
    int code;
1018
1019
125k
    data.cgp = cgp;
1020
125k
    data.pdfont = *ppdfont;
1021
125k
    data.char_code = char_code;
1022
125k
    data.glyph = glyph;
1023
125k
    data.font = font;
1024
125k
    pdev->find_resource_param = &data;
1025
125k
    code = pdf_find_same_charproc_aux(pdev, ppdfont, ppcp);
1026
125k
    pdev->find_resource_param = NULL;
1027
125k
    *ppdfont = data.pdfont;
1028
125k
    return code;
1029
125k
}
1030
1031
static bool
1032
pdf_is_charproc_defined(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, gs_char ch)
1033
10.6k
{
1034
10.6k
    pdf_char_proc_ownership_t *pcpo;
1035
1036
142k
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
1037
131k
        if (pcpo->char_code == ch)
1038
29
            return true;
1039
131k
    }
1040
10.6k
    return false;
1041
10.6k
}
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
125k
{
1048
125k
    pdf_font_resource_t *pdfont;
1049
125k
    double *real_widths;
1050
125k
    byte *glyph_usage;
1051
125k
    int char_cache_size, width_cache_size;
1052
125k
    pdf_encoding_element_t *pet;
1053
125k
    int code;
1054
1055
125k
    code = pdf_attached_font_resource(pdev, font, &pdfont,
1056
125k
                &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1057
125k
    if (code < 0)
1058
0
        return code;
1059
125k
    code = pdf_attach_charproc(pdev, pdfont, pcp, glyph, ch, gnstr);
1060
125k
    if (code < 0)
1061
0
        return code;
1062
125k
    if (ch >= char_cache_size || ch >= width_cache_size)
1063
0
        return_error(gs_error_unregistered); /* Must not happen. */
1064
125k
    pet = &pdfont->u.simple.Encoding[ch];
1065
125k
    pdfont->Widths[ch] = pcp->real_width.x;
1066
125k
    real_widths[ch * 2    ] = pcp->real_width.x;
1067
125k
    real_widths[ch * 2 + 1] = pcp->real_width.y;
1068
125k
    glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
1069
125k
    pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
1070
125k
    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
125k
    pet->glyph = glyph;
1075
125k
    pet->is_difference = true;
1076
125k
    if (pdfont->u.simple.LastChar < (int)ch)
1077
4.45k
        pdfont->u.simple.LastChar = (int)ch;
1078
125k
    if (pdfont->u.simple.FirstChar > (int)ch)
1079
3.07k
        pdfont->u.simple.FirstChar = (int)ch;
1080
125k
    return pdf_copy_string_to_encoding(pdev, (gs_const_string *)gnstr, pet);
1081
125k
}
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
125k
{
1115
125k
    int code;
1116
125k
    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
125k
    pdf_char_proc_t *pcp = (pdf_char_proc_t *)pres;
1121
125k
    pdf_font_resource_t *pdfont;
1122
125k
    gs_char ch = output_char_code;
1123
125k
    bool checking_glyph_variation = false;
1124
1125
125k
    if (ch == GS_NO_CHAR)
1126
0
        return_error(gs_error_unregistered); /* Must not happen. */
1127
125k
    if (ch >= 256)
1128
0
        return_error(gs_error_unregistered); /* Must not happen. */
1129
125k
    if (pres == NULL)
1130
0
        return_error(gs_error_unregistered); /* Must not happen. */
1131
125k
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
1132
125k
    if (code < 0)
1133
0
        return code;
1134
125k
    if (pdfont != (pdf_font_resource_t *)pdev->font3)
1135
14
        return_error(gs_error_unregistered); /* Must not happen. */
1136
125k
    code = pdf_exit_substream(pdev);
1137
125k
    if (code < 0)
1138
0
        return code;
1139
125k
    if (!(pdfont->used[ch >> 3] & (0x80 >> (ch & 7))) ||
1140
125k
        !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) {
1141
        /* First appearence or not cached - check for duplicates. */
1142
125k
        pdf_font_resource_t *pdfont1 = pdfont;
1143
1144
125k
        checking_glyph_variation = true;
1145
        /* CAUTION : a possible font change. */
1146
125k
        code = pdf_find_same_charproc(pdev, &pdfont, cgp, &pcp, glyph, ch, font);
1147
125k
        if (code < 0)
1148
0
            return code;
1149
125k
        if (code != 0) {
1150
115k
            code = pdf_cancel_resource(pdev, pres, resourceCharProc);
1151
115k
            if (code < 0)
1152
0
                return code;
1153
115k
            pdf_forget_resource(pdev, pres, resourceCharProc);
1154
115k
            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
115k
            pdev->charproc_just_accumulated = true;
1163
115k
            return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
1164
115k
        }
1165
10.6k
        if (pdf_is_charproc_defined(pdev, pdfont, ch)) {
1166
            /* Encoding conflict after a font change. */
1167
29
            gs_font *base_font = font, *below;
1168
1169
29
            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
29
            code = pdf_make_font3_resource(pdev, base_font, &pdfont);
1173
29
            if (code < 0)
1174
0
                return code;
1175
29
            code = pdf_attach_font_resource(pdev, font, pdfont);
1176
29
            if (code < 0)
1177
0
                return code;
1178
29
        }
1179
10.6k
    }
1180
10.6k
    pdf_reserve_object_id(pdev, pres, 0);
1181
10.6k
    if (checking_glyph_variation)
1182
10.6k
        pdev->charproc_just_accumulated = true;
1183
10.6k
    return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
1184
125k
}
1185
1186
/* Add procsets to substream Resources. */
1187
int
1188
pdf_add_procsets(cos_dict_t *pcd, pdf_procset_t procsets)
1189
17.8k
{
1190
17.8k
    char str[5 + 7 + 7 + 7 + 5 + 2];
1191
17.8k
    cos_value_t v;
1192
1193
17.8k
    strcpy(str, "[/PDF");
1194
17.8k
    if (procsets & ImageB)
1195
0
        strcat(str, "/ImageB");
1196
17.8k
    if (procsets & ImageC)
1197
1.74k
        strcat(str, "/ImageC");
1198
17.8k
    if (procsets & ImageI)
1199
8
        strcat(str, "/ImageI");
1200
17.8k
    if (procsets & Text)
1201
376
        strcat(str, "/Text");
1202
17.8k
    strcat(str, "]");
1203
17.8k
    cos_string_value(&v, (byte *)str, strlen(str));
1204
17.8k
    return cos_dict_put_c_key(pcd, "/ProcSet", &v);
1205
17.8k
}
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.10M
{
1211
1.10M
    if (pcd != 0) {
1212
41.7k
        const cos_value_t *v = cos_dict_find(pcd, (const byte *)key, strlen(key));
1213
41.7k
        cos_dict_t *list;
1214
41.7k
        int code;
1215
41.7k
        char buf[10 + (sizeof(long) * 8 / 3 + 1)], buf1[sizeof(pres->rname) + 1];
1216
1217
41.7k
        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
41.7k
        gs_snprintf(buf, sizeof(buf), "%"PRId64" 0 R\n", pres->object->id);
1224
41.7k
        if (v != NULL) {
1225
24.2k
            if (v->value_type != COS_VALUE_OBJECT &&
1226
0
                v->value_type != COS_VALUE_RESOURCE)
1227
0
                return_error(gs_error_unregistered); /* Must not happen. */
1228
24.2k
            list = (cos_dict_t *)v->contents.object;
1229
24.2k
            if (list->cos_procs != &cos_dict_procs)
1230
0
                return_error(gs_error_unregistered); /* Must not happen. */
1231
24.2k
        } else {
1232
17.4k
            list = cos_dict_alloc(pdev, "pdf_add_resource");
1233
17.4k
            if (list == NULL)
1234
0
                return_error(gs_error_VMerror);
1235
17.4k
            code = cos_dict_put_c_key_object((cos_dict_t *)pcd, key, (cos_object_t *)list);
1236
17.4k
            if (code < 0)
1237
0
                return code;
1238
17.4k
        }
1239
41.7k
        buf1[0] = '/';
1240
41.7k
        strcpy(buf1 + 1, pres->rname);
1241
41.7k
        return cos_dict_put_string(list, (const byte *)buf1, strlen(buf1),
1242
41.7k
                        (const byte *)buf, strlen(buf));
1243
41.7k
    }
1244
1.06M
    return 0;
1245
1.10M
}