Coverage Report

Created: 2025-11-16 07:40

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