Coverage Report

Created: 2026-09-14 07:34

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
212k
{
72
212k
    return pdf_resource_id((const pdf_resource_t *)pcp);
73
212k
}
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
91.6k
{
79
91.6k
    pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
80
91.6k
    pdf_font_resource_t *pdfont = pbfs->open_font; /* Type 3 */
81
91.6k
    int i, c = 0, code;
82
91.6k
    uint operation = pte->text.operation;
83
84
91.6k
    if (pbfs->bitmap_encoding_id == 0)
85
1.78k
        pbfs->bitmap_encoding_id = pdf_obj_ref(pdev);
86
91.6k
    if (pdfont == 0 || pdfont->u.simple.LastChar == 255 ||
87
89.7k
        !pbfs->use_open_font
88
91.6k
        ) {
89
        /* Start a new synthesized font. */
90
2.08k
        char *pc;
91
92
2.08k
        code = pdf_font_type3_alloc(pdev, &pdfont, pdf_write_contents_bitmap);
93
2.08k
        if (code < 0)
94
0
            return code;
95
2.08k
        pdfont->u.simple.s.type3.bitmap_font = true;
96
2.08k
        if (pbfs->open_font == 0)
97
1.78k
            pdfont->rname[0] = 0;
98
297
        else
99
297
            strcpy(pdfont->rname, pbfs->open_font->rname);
100
2.08k
        pdfont->u.simple.s.type3.FontBBox.p.x = 0;
101
2.08k
        pdfont->u.simple.s.type3.FontBBox.p.y = 0;
102
2.08k
        pdfont->u.simple.s.type3.FontBBox.q.x = 0;
103
2.08k
        pdfont->u.simple.s.type3.FontBBox.q.y = 0;
104
2.08k
        pdfont->mark_glyph = NULL;
105
2.08k
        gs_make_identity(&pdfont->u.simple.s.type3.FontMatrix);
106
        /*
107
         * We "increment" the font name as a radix-26 "number".
108
         * This cannot possibly overflow.
109
         */
110
2.08k
        for (pc = pdfont->rname; *pc == 'Z'; ++pc)
111
0
            *pc = '@';
112
2.08k
        if ((*pc)++ == 0)
113
1.78k
            *pc = 'A', pc[1] = 0;
114
2.08k
        pbfs->open_font = pdfont;
115
2.08k
        pbfs->use_open_font = true;
116
2.08k
        pdfont->u.simple.FirstChar = 255;
117
2.08k
    }
118
91.6k
    if ((operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) ||
119
91.6k
        (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR))) {
120
91.6k
        unsigned char p = *pte->text.data.bytes;
121
91.6k
        unsigned char index = p / 8, bit = 0x01 << (p % 8);
122
123
91.6k
        if (pdfont->used[index] & bit) {
124
6.27M
            for (i = 0;i < 256;i++) {
125
6.27M
                index = i / 8;
126
6.27M
                bit = 0x01 << (i % 8);
127
6.27M
                if (!(pdfont->used[index] & bit)) {
128
82.8k
                    c = i;
129
82.8k
                    break;
130
82.8k
                }
131
6.27M
            }
132
82.8k
        } else
133
8.79k
            c = p;
134
91.6k
        pdfont->used[index] |= bit;
135
91.6k
        if (c > pdfont->u.simple.LastChar)
136
62.9k
            pdfont->u.simple.LastChar = c;
137
138
91.6k
    } 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
91.6k
    if (c < pdfont->u.simple.FirstChar)
146
3.20k
        pdfont->u.simple.FirstChar = c;
147
148
91.6k
    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
91.6k
    if (c > pbfs->max_embedded_code)
152
50.6k
        pbfs->max_embedded_code = c;
153
154
91.6k
    return c;
155
91.6k
}
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.10k
{
161
3.10k
    stream *s = pdev->strm;
162
3.10k
    const pdf_char_proc_ownership_t *pcpo;
163
3.10k
    int64_t diff_id = 0;
164
3.10k
    int code;
165
166
3.10k
    if (pdfont->u.simple.s.type3.bitmap_font)
167
2.08k
        diff_id = pdev->text->bitmap_fonts->bitmap_encoding_id;
168
1.02k
    else {
169
        /* See comment in pdf_write_encoding. */
170
1.02k
        diff_id = pdf_obj_ref(pdev);
171
1.02k
    }
172
3.10k
    code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
173
3.10k
    if (code < 0)
174
0
        return code;
175
3.10k
    stream_puts(s, "/CharProcs <<");
176
    /* Write real characters. */
177
109k
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo;
178
106k
         pcpo = pcpo->char_next
179
106k
         ) {
180
106k
        if (pdfont->u.simple.s.type3.bitmap_font)
181
91.6k
            pprinti64d2(s, "/a%"PRId64" %"PRId64" 0 R\n", pcpo->char_code,
182
91.6k
                      pdf_char_proc_id(pcpo->char_proc));
183
14.7k
        else if (!pcpo-> duplicate_char_name) {
184
14.7k
            pdf_put_name(pdev, pcpo->char_name.data, pcpo->char_name.size);
185
14.7k
            pprinti64d1(s, " %"PRId64" 0 R\n", pdf_char_proc_id(pcpo->char_proc));
186
14.7k
        }
187
106k
        pdf_record_usage_by_parent(pdev, pdf_char_proc_id(pcpo->char_proc), pdfont->object->id);
188
106k
    }
189
3.10k
    stream_puts(s, ">>");
190
3.10k
    pprintg6(s, "/FontMatrix[%g %g %g %g %g %g]",
191
3.10k
            (float)pdfont->u.simple.s.type3.FontMatrix.xx,
192
3.10k
            (float)pdfont->u.simple.s.type3.FontMatrix.xy,
193
3.10k
            (float)pdfont->u.simple.s.type3.FontMatrix.yx,
194
3.10k
            (float)pdfont->u.simple.s.type3.FontMatrix.yy,
195
3.10k
            (float)pdfont->u.simple.s.type3.FontMatrix.tx,
196
3.10k
            (float)pdfont->u.simple.s.type3.FontMatrix.ty);
197
3.10k
    code = pdf_finish_write_contents_type3(pdev, pdfont);
198
3.10k
    if (code < 0)
199
0
        return code;
200
3.10k
    if (!pdfont->u.simple.s.type3.bitmap_font && diff_id > 0) {
201
1.02k
        code = pdf_write_encoding(pdev, pdfont, diff_id, 0);
202
1.02k
        if (code < 0)
203
0
            return code;
204
1.02k
    }
205
3.10k
    return 0;
206
3.10k
}
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
33.7k
{
216
33.7k
    pdf_bitmap_fonts_t *pbfs =
217
33.7k
        gs_alloc_struct(mem, pdf_bitmap_fonts_t, &st_pdf_bitmap_fonts,
218
33.7k
                        "pdf_bitmap_fonts_alloc");
219
220
33.7k
    if (pbfs == 0)
221
0
        return 0;
222
33.7k
    memset(pbfs, 0, sizeof(*pbfs));
223
33.7k
    pbfs->max_embedded_code = -1;
224
33.7k
    return pbfs;
225
33.7k
}
226
227
/*
228
 * Update text state at the end of a page.
229
 */
230
void
231
pdf_close_text_page(gx_device_pdf *pdev)
232
45.1k
{
233
    /*
234
     * When Acrobat Reader 3 prints a file containing a Type 3 font with a
235
     * non-standard Encoding, it apparently only emits the subset of the
236
     * font actually used on the page.  Thus, if the "Download Fonts Once"
237
     * option is selected, characters not used on the page where the font
238
     * first appears will not be defined, and hence will print as blank if
239
     * used on subsequent pages.  Thus, we can't allow a Type 3 font to
240
     * add additional characters on subsequent pages.
241
     */
242
45.1k
    if (pdev->CompatibilityLevel <= 1.2)
243
31.3k
        pdev->text->bitmap_fonts->use_open_font = false;
244
45.1k
}
245
246
int
247
pdf_charproc_y_offset(pdf_char_proc_t *pcp)
248
931k
{
249
931k
    return pcp->y_offset;
250
931k
}
251
252
int
253
pdf_charproc_x_offset(pdf_char_proc_t *pcp)
254
931k
{
255
931k
    return pcp->x_offset;
256
931k
}
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
167k
{
263
167k
    pdf_char_proc_ownership_t *pcpo;
264
167k
    bool duplicate_char_name = false;
265
266
8.76M
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
267
8.65M
        if (pcpo->glyph == glyph && pcpo->char_code == char_code)
268
57.7k
            return 0;
269
8.65M
    }
270
109k
    if (!pdfont->u.simple.s.type3.bitmap_font) {
271
536k
        for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
272
519k
            if (!bytes_compare(pcpo->char_name.data, pcpo->char_name.size, gnstr->data, gnstr->size)) {
273
55
                duplicate_char_name = true;
274
55
                break;
275
55
            }
276
519k
        }
277
17.7k
    }
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
91.6k
        pcpo->char_name.data = 0;
293
91.6k
        pcpo->char_name.size = 0;
294
91.6k
    } else {
295
17.7k
        if (gnstr->size > 0) {
296
17.7k
            pcpo->char_name.data = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, gnstr->size, "storage for charproc name");
297
17.7k
            if (pcpo->char_name.data == NULL)
298
0
                return_error(gs_error_VMerror);
299
17.7k
            memcpy(pcpo->char_name.data, gnstr->data, gnstr->size);
300
17.7k
        }
301
17.7k
        pcpo->char_name.size = gnstr->size;
302
17.7k
    }
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.15k
{
310
3.15k
    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
17.7k
            gs_free_object(pdev->pdf_memory->non_gc_memory, pcpo->char_name.data, "free storage for charproc naem");
316
            /* This causes PCL some trouble, don't know why yet FIXME-MEMORY
317
            gs_free_string(pdev->pdf_memory, (byte *)pcpo->char_name.data, pcpo->char_name.size, "Free CharProc name");*/
318
17.7k
            pcpo->char_name.data = (byte *)0L;
319
17.7k
            pcpo->char_name.size = 0;
320
17.7k
        }
321
109k
        gs_free_object(pdev->pdf_memory, pcpo, "Free CharProc");
322
109k
        pcpo = next;
323
109k
    }
324
3.15k
    return 0;
325
3.15k
}
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
91.6k
{
333
91.6k
    gs_char char_code = 0;
334
91.6k
    pdf_bitmap_fonts_t *const pbfs = pdev->text->bitmap_fonts;
335
91.6k
    pdf_font_resource_t *font;
336
91.6k
    pdf_resource_t *pres;
337
91.6k
    pdf_char_proc_t *pcp;
338
91.6k
    int code;
339
    /* This code added to store PCL bitmap glyphs in type 3 fonts where possible */
340
91.6k
    gs_glyph glyph = GS_NO_GLYPH;
341
91.6k
    gs_const_string str2, *str = NULL;
342
91.6k
    gs_show_enum *show_enum = (gs_show_enum *)pdev->pte;
343
91.6k
    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
91.6k
    int allowed_op = (show_enum->text.operation &
348
91.6k
        (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
91.6k
    if ((show_enum->current_font->FontType == ft_user_defined ||
361
91.6k
        show_enum->current_font->FontType == ft_PDF_user_defined ||
362
91.6k
        show_enum->current_font->FontType == ft_PCL_user_defined ||
363
91.6k
        show_enum->current_font->FontType == ft_MicroType ||
364
91.6k
        show_enum->current_font->FontType == ft_GL2_stick_user_defined ||
365
91.6k
        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
91.6k
    } else {
438
91.6k
        char_code = assign_char_code(pdev, pdev->pte);
439
91.6k
        font = pbfs->open_font; /* Type 3 */
440
91.6k
    }
441
442
91.6k
    code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
443
91.6k
    if (code < 0)
444
0
        return code;
445
91.6k
    pcp = (pdf_char_proc_t *) pres;
446
91.6k
    code = pdf_attach_charproc(pdev, font, pcp, glyph, char_code, str);
447
91.6k
    if (code < 0)
448
0
        return code;
449
91.6k
    pres->object->written = true;
450
91.6k
    {
451
91.6k
        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
91.6k
        stream_puts(s, "<</Length       >>stream\n");
461
91.6k
        ppos->start_pos = stell(s);
462
91.6k
    }
463
91.6k
    code = pdf_begin_encrypt(pdev, &pdev->strm, pres->object->id);
464
91.6k
    if (code < 0)
465
0
        return code;
466
91.6k
    pcp->y_offset = y_offset;
467
91.6k
    pcp->x_offset = x_offset;
468
91.6k
    font->u.simple.s.type3.FontBBox.q.x =
469
91.6k
        max(font->u.simple.s.type3.FontBBox.q.x, w);
470
91.6k
    font->u.simple.s.type3.FontBBox.q.y =
471
91.6k
        max(font->u.simple.s.type3.FontBBox.q.y, y_offset + h);
472
91.6k
    font->u.simple.s.type3.max_y_offset =
473
91.6k
        max(font->u.simple.s.type3.max_y_offset, h + (h >> 2));
474
91.6k
    pcp->real_width.x = w;
475
91.6k
    pcp->real_width.y = y_offset + h;
476
91.6k
    *ppcp = pcp;
477
91.6k
    return 0;
478
91.6k
}
479
480
/* End a CharProc. */
481
int
482
pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos)
483
91.6k
{
484
91.6k
    stream *s;
485
91.6k
    gs_offset_t start_pos, end_pos, length;
486
487
91.6k
    if (pdf_end_encrypt(pdev))
488
0
        s_close_filters(&pdev->strm, pdev->strm->strm);
489
490
91.6k
    s = pdev->strm;
491
91.6k
    start_pos = ppos->start_pos;
492
91.6k
    end_pos = stell(s);
493
91.6k
    length = end_pos - start_pos;
494
91.6k
    if (length > 999999)
495
0
        return_error(gs_error_limitcheck);
496
91.6k
    sseek(s, start_pos - 15);
497
91.6k
    pprintd1(s, "%d", length);
498
91.6k
    sseek(s, end_pos);
499
91.6k
    if (pdev->PDFA != 0)
500
0
        stream_puts(s, "\n");
501
91.6k
    stream_puts(s, "endstream\n");
502
91.6k
    pdf_end_separate(pdev, resourceCharProc);
503
91.6k
    return 0;
504
91.6k
}
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
28.5k
{
510
28.5k
    if (pdfont->mark_glyph == NULL) {
511
        /* Synthesised bitmap fonts pass here. */
512
26.6k
        return;
513
26.6k
    }
514
1.90k
    if (pdfont->u.simple.Encoding != NULL) {
515
1.90k
         int i;
516
517
488k
         for (i = 0; i < 256; i++)
518
486k
             if (pdfont->u.simple.Encoding[i].glyph != GS_NO_GLYPH)
519
71.4k
                pdfont->mark_glyph(memory, pdfont->u.simple.Encoding[i].glyph, pdfont->mark_glyph_data);
520
1.90k
     }
521
1.90k
    if (pdfont->FontType == ft_user_defined ||
522
1.53k
        pdfont->FontType == ft_PDF_user_defined ||
523
1.53k
        pdfont->FontType == ft_PCL_user_defined ||
524
1.53k
        pdfont->FontType == ft_MicroType ||
525
1.53k
        pdfont->FontType == ft_GL2_stick_user_defined ||
526
1.53k
        pdfont->FontType == ft_GL2_531) {
527
363
        const pdf_char_proc_ownership_t *pcpo = pdfont->u.simple.s.type3.char_procs;
528
529
6.57k
        for (; pcpo != NULL; pcpo = pcpo->font_next)
530
6.20k
            pdfont->mark_glyph(memory, pcpo->glyph, pdfont->mark_glyph_data);
531
363
    }
532
1.90k
}
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.02M
{
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.02M
    const pdf_char_proc_ownership_t * pcpo = pcp->owner_fonts;
543
1.02M
    pdf_font_resource_t *pdfont = pcpo->font;
544
1.02M
    byte ch = pcpo->char_code;
545
1.02M
    pdf_text_state_values_t values;
546
547
1.02M
    values.character_spacing = 0;
548
1.02M
    values.pdfont = pdfont;
549
1.02M
    values.size = 1;
550
1.02M
    values.matrix = *pimat;
551
1.02M
    values.render_mode = pdev->pte->pgs->text_rendering_mode;
552
1.02M
    values.word_spacing = 0;
553
1.02M
    pdf_set_text_state_values(pdev, &values);
554
1.02M
    pdf_bitmap_char_update_bbox(pdev, pcp->x_offset, pcp->y_offset, pcp->real_width.x, pcp->real_width.y);
555
1.02M
    pdf_append_chars(pdev, &ch, 1, pdfont->Widths[ch] * pimat->xx, 0.0, false);
556
1.02M
    return 0;
557
1.02M
}
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
33.7k
{
565
33.7k
    pdf_bitmap_fonts_t *pbfs;
566
567
33.7k
    if (pdev->text == NULL || pdev->text->bitmap_fonts == NULL)
568
0
        return 0;
569
570
33.7k
    pbfs = pdev->text->bitmap_fonts;
571
572
33.7k
    if (pbfs->bitmap_encoding_id) {
573
1.78k
        stream *s;
574
1.78k
        int i;
575
576
1.78k
        pdf_open_separate(pdev, pbfs->bitmap_encoding_id, resourceEncoding);
577
1.78k
        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.78k
        stream_puts(s, "<</Type/Encoding/Differences[0");
586
122k
        for (i = 0; i <= pbfs->max_embedded_code; ++i) {
587
120k
            if (!(i & 15))
588
8.43k
                stream_puts(s, "\n");
589
120k
            pprintd1(s, "/a%d", i);
590
120k
        }
591
1.78k
        stream_puts(s, "\n] >>\n");
592
1.78k
        pdf_end_separate(pdev, resourceEncoding);
593
1.78k
        pbfs->bitmap_encoding_id = 0;
594
1.78k
    }
595
33.7k
    return 0;
596
33.7k
}
597
598
/*
599
 * Start charproc accumulation for a Type 3 font.
600
 */
601
int
602
pdf_start_charproc_accum(gx_device_pdf *pdev)
603
75.5k
{
604
75.5k
    pdf_char_proc_t *pcp;
605
75.5k
    pdf_resource_t *pres;
606
75.5k
    int id = gs_next_ids(pdev->memory, 1);
607
75.5k
    int code = pdf_enter_substream(pdev, resourceCharProc, id,
608
75.5k
                                   &pres, false, pdev->CompressFonts);
609
610
75.5k
    if (code < 0)
611
0
       return code;
612
75.5k
    pres->rid = id;
613
75.5k
    pcp = (pdf_char_proc_t *)pres;
614
75.5k
    pcp->owner_fonts = NULL;
615
75.5k
    return 0;
616
75.5k
}
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
58.4k
{
625
58.4k
    pdf_font_resource_t *pdfont;
626
58.4k
    pdf_resource_t *pres = pdev->accumulating_substream_resource;
627
58.4k
    pdf_char_proc_t *pcp;
628
58.4k
    int code;
629
630
58.4k
    if (pres == NULL)
631
0
        return_error(gs_error_undefined);
632
58.4k
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
633
58.4k
    if (code < 0)
634
0
        return code;
635
58.4k
    pcp = (pdf_char_proc_t *)pres;
636
58.4k
    pcp->owner_fonts = NULL;
637
58.4k
    pcp->real_width.x = pw[font->WMode && narg > 6 ? 6 : 0];
638
58.4k
    pcp->real_width.y = pw[font->WMode && narg > 6 ? 7 : 1];
639
58.4k
    pcp->v.x = (narg > 8 ? pw[8] : 0);
640
58.4k
    pcp->v.y = (narg > 8 ? pw[9] : 0);
641
58.4k
    if (control == TEXT_SET_CHAR_WIDTH) {
642
        /* PLRM 5.7.1 "BuildGlyph" reads : "Normally, it is unnecessary and
643
        undesirable to initialize the current color parameter, because show
644
        is defined to paint glyphs with the current color."
645
        However comparefiles/Bug687044.ps doesn't follow that. */
646
49.4k
        pdev->skip_colors = false;
647
49.4k
        pprintg1(pdev->strm, "%g 0 d0\n", (float)pw[0]);
648
        /* The colour change described above can't affect PCL fonts and we need
649
         * all glyphs to be noted as cached in order for the bitmap font cache
650
         * probing to work properly.
651
         */
652
49.4k
        if (font->FontType == ft_PCL_user_defined || font->FontType == ft_GL2_stick_user_defined
653
49.4k
            || font->FontType == ft_GL2_531 || font->FontType == ft_MicroType)
654
0
            pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
655
49.4k
    } else {
656
9.03k
        double d;
657
9.03k
        pdev->skip_colors = true;
658
9.03k
        if (pw[4] < pw[2]) {
659
19
            d = pw[2];
660
19
            pw[2] = pw[4];
661
19
            pw[4] = d;
662
19
        }
663
9.03k
        if (pw[5] < pw[3]) {
664
29
            d = pw[5];
665
29
            pw[5] = pw[3];
666
29
            pw[3] = d;
667
29
        }
668
9.03k
        pprintg6(pdev->strm, "%g %g %g %g %g %g d1\n",
669
9.03k
            (float)pw[0], (float)0.0, (float)pw[2],
670
9.03k
            (float)pw[3], (float)pw[4], (float)pw[5]);
671
9.03k
        pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
672
9.03k
    }
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
58.4k
    if (scale_100) {
680
58.4k
    code = stream_puts(pdev->strm, "0.01 0 0 0.01 0 0 cm\n");
681
58.4k
    if (code < 0)
682
0
        return code;
683
58.4k
    }
684
58.4k
    return 0;
685
58.4k
}
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
154k
{
695
154k
    int code;
696
154k
    pdf_resource_t *pres;
697
154k
    stream *s, *save_strm = pdev->strm;
698
154k
    pdf_data_writer_t writer;
699
154k
    static const pdf_filter_names_t fnames = {
700
154k
        PDF_FILTER_NAMES
701
154k
    };
702
703
154k
    pdev->streams.save_strm = pdev->strm;
704
705
154k
    if (rtype >= NUM_RESOURCE_TYPES)
706
39.7k
        rtype = resourceOther;
707
154k
    code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id),
708
154k
                pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1);
709
154k
    if (code < 0)
710
0
        return code;
711
154k
    cos_become(pres->object, cos_type_stream);
712
154k
    s = cos_write_stream_alloc((cos_stream_t *)pres->object, pdev, "pdf_enter_substream");
713
154k
    if (s == 0)
714
0
        return_error(gs_error_VMerror);
715
154k
    pdev->strm = s;
716
154k
    code = pdf_append_data_stream_filters(pdev, &writer,
717
154k
                             options | DATA_STREAM_NOLENGTH, pres->object->id);
718
154k
    if (code < 0) {
719
0
        pdev->strm = save_strm;
720
0
        return code;
721
0
    }
722
154k
    code = pdf_put_filters((cos_dict_t *)pres->object, pdev, writer.binary.strm, &fnames);
723
154k
    if (code < 0) {
724
0
        pdev->strm = save_strm;
725
0
        return code;
726
0
    }
727
154k
    pdev->strm = writer.binary.strm;
728
154k
    *ppres = pres;
729
154k
    return 0;
730
154k
}
731
732
/*
733
 * Close a stream object in the temporary file.
734
 */
735
int
736
pdf_close_aside(gx_device_pdf *pdev)
737
154k
{
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
154k
    stream *s = pdev->strm;
742
154k
    cos_stream_t *pcs = cos_stream_from_pipeline(s);
743
154k
    int status = s_close_filters(&s, NULL);
744
745
154k
    pdev->strm = pdev->streams.save_strm;
746
154k
    if (status < 0)
747
0
         return(gs_note_error(gs_error_ioerror));
748
749
154k
    if (!pcs)
750
0
        return gs_note_error(gs_error_ioerror);
751
752
154k
    pcs->is_open = false;
753
154k
    return 0;
754
154k
}
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
114k
{
763
114k
    int sbstack_ptr = pdev->sbstack_depth;
764
114k
    pdf_resource_t *pres;
765
114k
    stream *save_strm = pdev->strm;
766
114k
    int code;
767
768
114k
    if (pdev->sbstack_depth >= pdev->sbstack_size)
769
0
        return_error(gs_error_unregistered); /* Must not happen. */
770
114k
    if (pdev->sbstack[sbstack_ptr].text_state == 0) {
771
114k
        pdev->sbstack[sbstack_ptr].text_state = pdf_text_state_alloc(pdev->pdf_memory);
772
114k
        if (pdev->sbstack[sbstack_ptr].text_state == 0)
773
0
            return_error(gs_error_VMerror);
774
114k
    }
775
114k
    code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id,
776
114k
                    (compress ? DATA_STREAM_COMPRESS : 0));
777
114k
    if (code < 0)
778
0
        return code;
779
114k
    code = pdf_save_viewer_state(pdev, NULL);
780
114k
    if (code < 0) {
781
0
        pdev->strm = save_strm;
782
0
        return code;
783
0
    }
784
114k
    pdev->sbstack[sbstack_ptr].context = pdev->context;
785
114k
    pdf_text_state_copy(pdev->sbstack[sbstack_ptr].text_state, pdev->text->text_state);
786
114k
    pdf_set_text_state_default(pdev->text->text_state);
787
114k
    pdev->sbstack[sbstack_ptr].clip_path = pdev->clip_path;
788
114k
    pdev->clip_path = 0;
789
114k
    pdev->sbstack[sbstack_ptr].clip_path_id = pdev->clip_path_id;
790
114k
    pdev->clip_path_id = pdev->no_clip_path_id;
791
114k
    pdev->sbstack[sbstack_ptr].vgstack_bottom = pdev->vgstack_bottom;
792
114k
    pdev->vgstack_bottom = pdev->vgstack_depth;
793
114k
    pdev->sbstack[sbstack_ptr].strm = save_strm;
794
114k
    pdev->sbstack[sbstack_ptr].procsets = pdev->procsets;
795
114k
    pdev->sbstack[sbstack_ptr].substream_Resources = pdev->substream_Resources;
796
114k
    pdev->sbstack[sbstack_ptr].skip_colors = pdev->skip_colors;
797
114k
    pdev->sbstack[sbstack_ptr].font3 = pdev->font3;
798
114k
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = pdev->accumulating_substream_resource;
799
114k
    pdev->sbstack[sbstack_ptr].charproc_just_accumulated = pdev->charproc_just_accumulated;
800
114k
    pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object;
801
114k
    pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict;
802
114k
    pdev->sbstack[sbstack_ptr].objname = pdev->objname;
803
114k
    pdev->sbstack[sbstack_ptr].last_charpath_op = pdev->last_charpath_op;
804
114k
    pdev->skip_colors = false;
805
114k
    pdev->charproc_just_accumulated = false;
806
114k
    pdev->pres_soft_mask_dict = NULL;
807
114k
    pdev->objname.data = NULL;
808
114k
    pdev->objname.size = 0;
809
    /* Do not reset pdev->accumulating_a_global_object - it inherits. */
810
114k
    pdev->sbstack_depth++;
811
114k
    pdev->procsets = 0;
812
114k
    pdev->font3 = 0;
813
114k
    pdev->context = PDF_IN_STREAM;
814
114k
    pdev->accumulating_substream_resource = pres;
815
114k
    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
114k
    if (rtype != resourceXObject)
820
110k
        pdf_reset_graphics(pdev);
821
3.47k
    else {
822
3.47k
        if (pdev->vg_initial_set)
823
3.47k
            pdev->state.blend_mode = pdev->vg_initial.blend_mode;
824
3.47k
    }
825
114k
    *ppres = pres;
826
114k
    return 0;
827
114k
}
828
829
/*
830
 * Exit the substream accumulation mode.
831
 */
832
int
833
pdf_exit_substream(gx_device_pdf *pdev)
834
114k
{
835
114k
    int code, code1;
836
114k
    int sbstack_ptr;
837
838
114k
    if (pdev->sbstack_depth <= 0)
839
0
        return_error(gs_error_unregistered); /* Must not happen. */
840
114k
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
841
114k
    sbstack_ptr = pdev->sbstack_depth - 1;
842
118k
    while (pdev->vgstack_depth > pdev->vgstack_bottom) {
843
3.91k
        code1 = pdf_restore_viewer_state(pdev, pdev->strm);
844
3.91k
        if (code >= 0)
845
3.91k
            code = code1;
846
3.91k
    }
847
114k
    if (pdev->clip_path != 0)
848
0
        gx_path_free(pdev->clip_path, "pdf_end_charproc_accum");
849
114k
    code1 = pdf_close_aside(pdev);
850
114k
    if (code1 < 0 && code >= 0)
851
0
        code = code1;
852
114k
    pdev->context = pdev->sbstack[sbstack_ptr].context;
853
114k
    pdf_text_state_copy(pdev->text->text_state, pdev->sbstack[sbstack_ptr].text_state);
854
114k
    gs_free_object(pdev->pdf_memory, pdev->sbstack[sbstack_ptr].text_state, "free text state for stream");
855
114k
    pdev->sbstack[sbstack_ptr].text_state = 0;
856
114k
    pdev->clip_path = pdev->sbstack[sbstack_ptr].clip_path;
857
114k
    pdev->sbstack[sbstack_ptr].clip_path = 0;
858
114k
    pdev->clip_path_id = pdev->sbstack[sbstack_ptr].clip_path_id;
859
114k
    pdev->vgstack_bottom = pdev->sbstack[sbstack_ptr].vgstack_bottom;
860
114k
    pdev->strm = pdev->sbstack[sbstack_ptr].strm;
861
114k
    pdev->sbstack[sbstack_ptr].strm = 0;
862
114k
    pdev->procsets = pdev->sbstack[sbstack_ptr].procsets;
863
114k
    pdev->substream_Resources = pdev->sbstack[sbstack_ptr].substream_Resources;
864
114k
    pdev->sbstack[sbstack_ptr].substream_Resources = 0;
865
114k
    pdev->skip_colors = pdev->sbstack[sbstack_ptr].skip_colors;
866
114k
    pdev->font3 = pdev->sbstack[sbstack_ptr].font3;
867
114k
    pdev->sbstack[sbstack_ptr].font3 = 0;
868
114k
    pdev->accumulating_substream_resource = pdev->sbstack[sbstack_ptr].accumulating_substream_resource;
869
114k
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = 0;
870
114k
    pdev->charproc_just_accumulated = pdev->sbstack[sbstack_ptr].charproc_just_accumulated;
871
114k
    pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object;
872
114k
    pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict;
873
114k
    pdev->objname = pdev->sbstack[sbstack_ptr].objname;
874
114k
    pdev->last_charpath_op = pdev->sbstack[sbstack_ptr].last_charpath_op;
875
114k
    pdev->sbstack_depth = sbstack_ptr;
876
114k
    code1 = pdf_restore_viewer_state(pdev, NULL);
877
114k
    if (code1 < 0 && code >= 0)
878
0
        code = code1;
879
114k
    return code;
880
114k
}
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
247k
{
885
247k
    if (pcp0->real_width.x != pcp1->real_width.x)
886
164k
        return false;
887
82.6k
    if (pcp0->real_width.y != pcp1->real_width.y)
888
0
        return false;
889
82.6k
    if (pcp0->v.x != pcp1->v.x)
890
0
        return false;
891
82.6k
    if (pcp0->v.y != pcp1->v.y)
892
0
        return false;
893
82.6k
    return true;
894
82.6k
}
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
144
{
907
144
    pdf_char_proc_ownership_t *pcpo;
908
909
1.13k
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
910
997
        if (pcpo->char_code == char_code) {
911
2
            return true;
912
2
        }
913
997
    }
914
142
    return false;
915
144
}
916
917
static int
918
pdf_is_charproc_compatible(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
919
144
{
920
144
    charproc_compatibility_data_t *data = (charproc_compatibility_data_t *)pdev->find_resource_param;
921
144
    pdf_char_proc_t *pcp0 = (pdf_char_proc_t *)pres0;
922
144
    pdf_char_proc_t *pcp1 = (pdf_char_proc_t *)pres1;
923
144
    pdf_font_resource_t *pdfont = data->pdfont;
924
144
    pdf_char_proc_ownership_t *pcpo;
925
144
    pdf_font_cache_elem_t **e;
926
144
    bool can_add_to_current_font = false, computed_can_add_to_current_font = false;
927
928
    /* Does it have same attributes ? */
929
144
    if (!pdf_is_same_charproc_attrs1(pdev, pcp0, pcp1))
930
0
        return 0;
931
    /* Is it from same font ? */
932
1.81k
    for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
933
1.67k
        if (pdfont == pcpo->font) {
934
            /* Check for encoding conflict. */
935
0
            if (pcpo->char_code == data->char_code && pcpo->glyph == data->glyph)
936
0
                return 1; /* Same char code. */
937
0
            if (!computed_can_add_to_current_font) {
938
0
                can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
939
0
                computed_can_add_to_current_font = true;
940
0
            }
941
0
            if (can_add_to_current_font)
942
0
                return 1; /* No conflict. */
943
0
        }
944
1.67k
    }
945
    /* Look for another font with same encoding,
946
       because we want to reduce the number of new fonts.
947
       We also restrict with ones attached to same PS font,
948
       otherwise it creates too mixed fonts and disturbs word breaks.
949
     */
950
144
    e = pdf_locate_font_cache_elem(pdev, data->font);
951
144
    if (e != NULL) {
952
1.81k
        for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
953
1.67k
            if (pcpo->char_code != data->char_code || pcpo->glyph != data->glyph)
954
1.60k
                continue; /* Need same Encoding to generate a proper ToUnicode. */
955
67
            if (pdfont->u.simple.s.type3.bitmap_font != pcpo->font->u.simple.s.type3.bitmap_font)
956
0
                continue;
957
67
            if (gs_matrix_compare(&pdfont->u.simple.s.type3.FontMatrix, &pcpo->font->u.simple.s.type3.FontMatrix))
958
20
                continue;
959
47
            if (data->cgp != NULL) {
960
45
                if (!pdf_check_encoding_compatibility(pcpo->font, data->cgp->s, data->cgp->num_all_chars))
961
0
                    continue;
962
45
            }
963
47
            if ((*e)->pdfont != pcpo->font)
964
47
                continue;
965
0
            data->pdfont = pcpo->font; /* Switch to the other font. */
966
0
            return 1;
967
47
        }
968
144
    }
969
    /* Check whether it can be added into the current font. */
970
144
    if (!computed_can_add_to_current_font)
971
144
        can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
972
144
    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
142
    return 1;
978
144
}
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
75.5k
{
984
75.5k
    pdf_char_proc_ownership_t *pcpo;
985
75.5k
    int code;
986
987
    /* fixme: this passes parameters to pdf_is_charproc_compatible
988
       through special gx_device_pdf field pdev->find_resource_param
989
       due to prototype limitation of pdf_find_same_resource.
990
       It would be better to change the client data argument type in there to void. */
991
256k
    for (pcpo = (*ppdfont)->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
992
246k
        pdf_char_proc_t *pcp = pcpo->char_proc;
993
994
246k
        if (*ppcp != pcp && pdf_is_same_charproc_attrs1(pdev, *ppcp, pcp)) {
995
82.5k
            cos_object_t *pco0 = pcp->object;
996
82.5k
            cos_object_t *pco1 = (*ppcp)->object;
997
998
82.5k
            code = pco0->cos_procs->equal(pco0, pco1, pdev);
999
82.5k
            if (code < 0) {
1000
0
                return code;
1001
0
            }
1002
82.5k
            if (code) {
1003
66.0k
                *ppcp = pcp;
1004
66.0k
                return 1;
1005
66.0k
            }
1006
82.5k
        }
1007
246k
    }
1008
9.49k
    return pdf_find_same_resource(pdev, resourceCharProc, (pdf_resource_t **)ppcp, pdf_is_charproc_compatible);
1009
75.5k
}
1010
static int
1011
pdf_find_same_charproc(gx_device_pdf *pdev,
1012
            pdf_font_resource_t **ppdfont, const pdf_char_glyph_pairs_t *cgp,
1013
            pdf_char_proc_t **ppcp, gs_glyph glyph, gs_char char_code,
1014
            gs_font *font)
1015
75.5k
{
1016
75.5k
    charproc_compatibility_data_t data;
1017
75.5k
    int code;
1018
1019
75.5k
    data.cgp = cgp;
1020
75.5k
    data.pdfont = *ppdfont;
1021
75.5k
    data.char_code = char_code;
1022
75.5k
    data.glyph = glyph;
1023
75.5k
    data.font = font;
1024
75.5k
    pdev->find_resource_param = &data;
1025
75.5k
    code = pdf_find_same_charproc_aux(pdev, ppdfont, ppcp);
1026
75.5k
    pdev->find_resource_param = NULL;
1027
75.5k
    *ppdfont = data.pdfont;
1028
75.5k
    return code;
1029
75.5k
}
1030
1031
static bool
1032
pdf_is_charproc_defined(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, gs_char ch)
1033
9.35k
{
1034
9.35k
    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
30
            return true;
1039
119k
    }
1040
9.32k
    return false;
1041
9.35k
}
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
75.5k
{
1048
75.5k
    pdf_font_resource_t *pdfont;
1049
75.5k
    double *real_widths;
1050
75.5k
    byte *glyph_usage;
1051
75.5k
    int char_cache_size, width_cache_size;
1052
75.5k
    pdf_encoding_element_t *pet;
1053
75.5k
    int code;
1054
1055
75.5k
    code = pdf_attached_font_resource(pdev, font, &pdfont,
1056
75.5k
                &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1057
75.5k
    if (code < 0)
1058
0
        return code;
1059
75.5k
    code = pdf_attach_charproc(pdev, pdfont, pcp, glyph, ch, gnstr);
1060
75.5k
    if (code < 0)
1061
0
        return code;
1062
75.5k
    if (ch >= char_cache_size || ch >= width_cache_size)
1063
0
        return_error(gs_error_unregistered); /* Must not happen. */
1064
75.5k
    pet = &pdfont->u.simple.Encoding[ch];
1065
75.5k
    pdfont->Widths[ch] = pcp->real_width.x;
1066
75.5k
    real_widths[ch * 2    ] = pcp->real_width.x;
1067
75.5k
    real_widths[ch * 2 + 1] = pcp->real_width.y;
1068
75.5k
    glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
1069
75.5k
    pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
1070
75.5k
    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
75.5k
    pet->glyph = glyph;
1075
75.5k
    pet->is_difference = true;
1076
75.5k
    if (pdfont->u.simple.LastChar < (int)ch)
1077
3.59k
        pdfont->u.simple.LastChar = (int)ch;
1078
75.5k
    if (pdfont->u.simple.FirstChar > (int)ch)
1079
2.26k
        pdfont->u.simple.FirstChar = (int)ch;
1080
75.5k
    return pdf_copy_string_to_encoding(pdev, (gs_const_string *)gnstr, pet);
1081
75.5k
}
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
75.5k
{
1115
75.5k
    int code;
1116
75.5k
    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
75.5k
    pdf_char_proc_t *pcp = (pdf_char_proc_t *)pres;
1121
75.5k
    pdf_font_resource_t *pdfont;
1122
75.5k
    gs_char ch = output_char_code;
1123
75.5k
    bool checking_glyph_variation = false;
1124
1125
75.5k
    if (ch == GS_NO_CHAR)
1126
0
        return_error(gs_error_unregistered); /* Must not happen. */
1127
75.5k
    if (ch >= 256)
1128
0
        return_error(gs_error_unregistered); /* Must not happen. */
1129
75.5k
    if (pres == NULL)
1130
0
        return_error(gs_error_unregistered); /* Must not happen. */
1131
75.5k
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
1132
75.5k
    if (code < 0)
1133
0
        return code;
1134
75.5k
    if (pdfont != (pdf_font_resource_t *)pdev->font3)
1135
14
        return_error(gs_error_unregistered); /* Must not happen. */
1136
75.5k
    code = pdf_exit_substream(pdev);
1137
75.5k
    if (code < 0)
1138
0
        return code;
1139
75.5k
    if (!(pdfont->used[ch >> 3] & (0x80 >> (ch & 7))) ||
1140
75.5k
        !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) {
1141
        /* First appearence or not cached - check for duplicates. */
1142
75.5k
        pdf_font_resource_t *pdfont1 = pdfont;
1143
1144
75.5k
        checking_glyph_variation = true;
1145
        /* CAUTION : a possible font change. */
1146
75.5k
        code = pdf_find_same_charproc(pdev, &pdfont, cgp, &pcp, glyph, ch, font);
1147
75.5k
        if (code < 0)
1148
0
            return code;
1149
75.5k
        if (code != 0) {
1150
66.1k
            code = pdf_cancel_resource(pdev, pres, resourceCharProc);
1151
66.1k
            if (code < 0)
1152
0
                return code;
1153
66.1k
            pdf_forget_resource(pdev, pres, resourceCharProc);
1154
66.1k
            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
66.1k
            pdev->charproc_just_accumulated = true;
1163
66.1k
            return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
1164
66.1k
        }
1165
9.35k
        if (pdf_is_charproc_defined(pdev, pdfont, ch)) {
1166
            /* Encoding conflict after a font change. */
1167
30
            gs_font *base_font = font, *below;
1168
1169
30
            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
30
            code = pdf_make_font3_resource(pdev, base_font, &pdfont);
1173
30
            if (code < 0)
1174
0
                return code;
1175
30
            code = pdf_attach_font_resource(pdev, font, pdfont);
1176
30
            if (code < 0)
1177
0
                return code;
1178
30
        }
1179
9.35k
    }
1180
9.36k
    pdf_reserve_object_id(pdev, pres, 0);
1181
9.36k
    if (checking_glyph_variation)
1182
9.35k
        pdev->charproc_just_accumulated = true;
1183
9.36k
    return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
1184
75.5k
}
1185
1186
/* Add procsets to substream Resources. */
1187
int
1188
pdf_add_procsets(cos_dict_t *pcd, pdf_procset_t procsets)
1189
6.34k
{
1190
6.34k
    char str[5 + 7 + 7 + 7 + 5 + 2];
1191
6.34k
    cos_value_t v;
1192
1193
6.34k
    strcpy(str, "[/PDF");
1194
6.34k
    if (procsets & ImageB)
1195
0
        strcat(str, "/ImageB");
1196
6.34k
    if (procsets & ImageC)
1197
2.48k
        strcat(str, "/ImageC");
1198
6.34k
    if (procsets & ImageI)
1199
5
        strcat(str, "/ImageI");
1200
6.34k
    if (procsets & Text)
1201
77
        strcat(str, "/Text");
1202
6.34k
    strcat(str, "]");
1203
6.34k
    cos_string_value(&v, (byte *)str, strlen(str));
1204
6.34k
    return cos_dict_put_c_key(pcd, "/ProcSet", &v);
1205
6.34k
}
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.08M
{
1211
1.08M
    if (pcd != 0) {
1212
25.5k
        const cos_value_t *v = cos_dict_find(pcd, (const byte *)key, strlen(key));
1213
25.5k
        cos_dict_t *list;
1214
25.5k
        int code;
1215
25.5k
        char buf[10 + (sizeof(long) * 8 / 3 + 1)], buf1[sizeof(pres->rname) + 1];
1216
1217
25.5k
        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
25.5k
        gs_snprintf(buf, sizeof(buf), "%"PRId64" 0 R\n", pres->object->id);
1224
25.5k
        if (v != NULL) {
1225
15.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
15.6k
            list = (cos_dict_t *)v->contents.object;
1229
15.6k
            if (list->cos_procs != &cos_dict_procs)
1230
0
                return_error(gs_error_unregistered); /* Must not happen. */
1231
15.6k
        } else {
1232
9.87k
            list = cos_dict_alloc(pdev, "pdf_add_resource");
1233
9.87k
            if (list == NULL)
1234
0
                return_error(gs_error_VMerror);
1235
9.87k
            code = cos_dict_put_c_key_object((cos_dict_t *)pcd, key, (cos_object_t *)list);
1236
9.87k
            if (code < 0)
1237
0
                return code;
1238
9.87k
        }
1239
25.5k
        buf1[0] = '/';
1240
25.5k
        strcpy(buf1 + 1, pres->rname);
1241
25.5k
        return cos_dict_put_string(list, (const byte *)buf1, strlen(buf1),
1242
25.5k
                        (const byte *)buf, strlen(buf));
1243
25.5k
    }
1244
1.05M
    return 0;
1245
1.08M
}