Coverage Report

Created: 2025-04-22 06:20

/src/libspectre/ghostscript/devices/vector/gdevpdti.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2020 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, 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 long
70
pdf_char_proc_id(const pdf_char_proc_t *pcp)
71
0
{
72
0
    return pdf_resource_id((const pdf_resource_t *)pcp);
73
0
}
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
0
{
79
0
    pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
80
0
    pdf_font_resource_t *pdfont = pbfs->open_font; /* Type 3 */
81
0
    int i, c = 0, code;
82
0
    uint operation = pte->text.operation;
83
84
0
    if (pbfs->bitmap_encoding_id == 0)
85
0
        pbfs->bitmap_encoding_id = pdf_obj_ref(pdev);
86
0
    if (pdfont == 0 || pdfont->u.simple.LastChar == 255 ||
87
0
        !pbfs->use_open_font
88
0
        ) {
89
        /* Start a new synthesized font. */
90
0
        char *pc;
91
92
0
        code = pdf_font_type3_alloc(pdev, &pdfont, pdf_write_contents_bitmap);
93
0
        if (code < 0)
94
0
            return code;
95
0
        pdfont->u.simple.s.type3.bitmap_font = true;
96
0
        if (pbfs->open_font == 0)
97
0
            pdfont->rname[0] = 0;
98
0
        else
99
0
            strcpy(pdfont->rname, pbfs->open_font->rname);
100
0
        pdfont->u.simple.s.type3.FontBBox.p.x = 0;
101
0
        pdfont->u.simple.s.type3.FontBBox.p.y = 0;
102
0
        pdfont->u.simple.s.type3.FontBBox.q.x = 0;
103
0
        pdfont->u.simple.s.type3.FontBBox.q.y = 0;
104
0
        pdfont->mark_glyph = NULL;
105
0
        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
0
        for (pc = pdfont->rname; *pc == 'Z'; ++pc)
111
0
            *pc = '@';
112
0
        if ((*pc)++ == 0)
113
0
            *pc = 'A', pc[1] = 0;
114
0
        pbfs->open_font = pdfont;
115
0
        pbfs->use_open_font = true;
116
0
        pdfont->u.simple.FirstChar = 255;
117
0
    }
118
0
    if ((operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) ||
119
0
        (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR))) {
120
0
        unsigned char p = *pte->text.data.bytes;
121
0
        unsigned char index = p / 8, bit = 0x01 << (p % 8);
122
123
0
        if (pdfont->used[index] & bit) {
124
0
            for (i = 0;i < 256;i++) {
125
0
                index = i / 8;
126
0
                bit = 0x01 << (i % 8);
127
0
                if (!(pdfont->used[index] & bit)) {
128
0
                    c = i;
129
0
                    break;
130
0
                }
131
0
            }
132
0
        } else
133
0
            c = p;
134
0
        pdfont->used[index] |= bit;
135
0
        if (c > pdfont->u.simple.LastChar)
136
0
            pdfont->u.simple.LastChar = c;
137
138
0
    } 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
0
    if (c < pdfont->u.simple.FirstChar)
146
0
        pdfont->u.simple.FirstChar = c;
147
148
0
    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
0
    if (c > pbfs->max_embedded_code)
152
0
        pbfs->max_embedded_code = c;
153
154
0
    return c;
155
0
}
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
0
{
161
0
    stream *s = pdev->strm;
162
0
    const pdf_char_proc_ownership_t *pcpo;
163
0
    long diff_id = 0;
164
0
    int code;
165
166
0
    if (pdfont->u.simple.s.type3.bitmap_font)
167
0
        diff_id = pdev->text->bitmap_fonts->bitmap_encoding_id;
168
0
    else {
169
        /* See comment in pdf_write_encoding. */
170
0
        diff_id = pdf_obj_ref(pdev);
171
0
    }
172
0
    code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
173
0
    if (code < 0)
174
0
        return code;
175
0
    stream_puts(s, "/CharProcs <<");
176
    /* Write real characters. */
177
0
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo;
178
0
         pcpo = pcpo->char_next
179
0
         ) {
180
0
        if (pdfont->u.simple.s.type3.bitmap_font)
181
0
            pprintld2(s, "/a%ld %ld 0 R\n", (long)pcpo->char_code,
182
0
                      pdf_char_proc_id(pcpo->char_proc));
183
0
        else if (!pcpo-> duplicate_char_name) {
184
0
            pdf_put_name(pdev, pcpo->char_name.data, pcpo->char_name.size);
185
0
            pprintld1(s, " %ld 0 R\n", pdf_char_proc_id(pcpo->char_proc));
186
0
        }
187
0
        pdf_record_usage_by_parent(pdev, pdf_char_proc_id(pcpo->char_proc), pdfont->object->id);
188
0
    }
189
0
    stream_puts(s, ">>");
190
0
    pprintg6(s, "/FontMatrix[%g %g %g %g %g %g]",
191
0
            (float)pdfont->u.simple.s.type3.FontMatrix.xx,
192
0
            (float)pdfont->u.simple.s.type3.FontMatrix.xy,
193
0
            (float)pdfont->u.simple.s.type3.FontMatrix.yx,
194
0
            (float)pdfont->u.simple.s.type3.FontMatrix.yy,
195
0
            (float)pdfont->u.simple.s.type3.FontMatrix.tx,
196
0
            (float)pdfont->u.simple.s.type3.FontMatrix.ty);
197
0
    code = pdf_finish_write_contents_type3(pdev, pdfont);
198
0
    if (code < 0)
199
0
        return code;
200
0
    if (!pdfont->u.simple.s.type3.bitmap_font && diff_id > 0) {
201
0
        code = pdf_write_encoding(pdev, pdfont, diff_id, 0);
202
0
        if (code < 0)
203
0
            return code;
204
0
    }
205
0
    return 0;
206
0
}
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
0
{
216
0
    pdf_bitmap_fonts_t *pbfs =
217
0
        gs_alloc_struct(mem, pdf_bitmap_fonts_t, &st_pdf_bitmap_fonts,
218
0
                        "pdf_bitmap_fonts_alloc");
219
220
0
    if (pbfs == 0)
221
0
        return 0;
222
0
    memset(pbfs, 0, sizeof(*pbfs));
223
0
    pbfs->max_embedded_code = -1;
224
0
    return pbfs;
225
0
}
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
0
{
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
0
    if (pdev->CompatibilityLevel <= 1.2)
243
0
        pdev->text->bitmap_fonts->use_open_font = false;
244
0
}
245
246
int
247
pdf_charproc_y_offset(pdf_char_proc_t *pcp)
248
0
{
249
0
    return pcp->y_offset;
250
0
}
251
252
int
253
pdf_charproc_x_offset(pdf_char_proc_t *pcp)
254
0
{
255
0
    return pcp->x_offset;
256
0
}
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
0
{
263
0
    pdf_char_proc_ownership_t *pcpo;
264
0
    bool duplicate_char_name = false;
265
266
0
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
267
0
        if (pcpo->glyph == glyph && pcpo->char_code == char_code)
268
0
            return 0;
269
0
    }
270
0
    if (!pdfont->u.simple.s.type3.bitmap_font) {
271
0
        for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
272
0
            if (!bytes_compare(pcpo->char_name.data, pcpo->char_name.size, gnstr->data, gnstr->size)) {
273
0
                duplicate_char_name = true;
274
0
                break;
275
0
            }
276
0
        }
277
0
    }
278
0
    pcpo = gs_alloc_struct(pdev->pdf_memory,
279
0
            pdf_char_proc_ownership_t, &st_pdf_char_proc_ownership, "pdf_attach_charproc");
280
281
0
    if (pcpo == NULL)
282
0
        return_error(gs_error_VMerror);
283
0
    pcpo->font = pdfont;
284
0
    pcpo->char_next = pdfont->u.simple.s.type3.char_procs;
285
0
    pdfont->u.simple.s.type3.char_procs = pcpo;
286
0
    pcpo->char_proc = pcp;
287
0
    pcpo->font_next = pcp->owner_fonts;
288
0
    pcp->owner_fonts = pcpo;
289
0
    pcpo->char_code = char_code;
290
0
    pcpo->glyph = glyph;
291
0
    if (gnstr == NULL) {
292
0
        pcpo->char_name.data = 0;
293
0
        pcpo->char_name.size = 0;
294
0
    } else {
295
0
        pcpo->char_name.data = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, gnstr->size, "storage for charproc name");
296
0
        memcpy(pcpo->char_name.data, gnstr->data, gnstr->size);
297
0
        pcpo->char_name.size = gnstr->size;
298
//        pcpo->char_name = *gnstr;
299
0
    }
300
0
    pcpo->duplicate_char_name = duplicate_char_name;
301
0
    return 0;
302
0
}
303
304
int
305
pdf_free_charproc_ownership(gx_device_pdf * pdev, pdf_resource_t *pres)
306
0
{
307
0
    pdf_char_proc_ownership_t *next, *pcpo = (pdf_char_proc_ownership_t *)pres;
308
309
0
    while (pcpo) {
310
0
        next = pcpo->char_next;
311
0
        if(pcpo->char_name.size != 0 && pcpo->char_name.data) {
312
0
            gs_free_object(pdev->pdf_memory->non_gc_memory, pcpo->char_name.data, "free storage for charproc naem");
313
            /* This causes PCL some trouble, don't know why yet FIXME-MEMORY
314
            gs_free_string(pdev->pdf_memory, (byte *)pcpo->char_name.data, pcpo->char_name.size, "Free CharProc name");*/
315
0
            pcpo->char_name.data = (byte *)0L;
316
0
            pcpo->char_name.size = 0;
317
0
        }
318
0
        gs_free_object(pdev->pdf_memory, pcpo, "Free CharProc");
319
0
        pcpo = next;
320
0
    }
321
0
    return 0;
322
0
}
323
324
/* Begin a CharProc for a synthesized (bitmap) font. */
325
int
326
pdf_begin_char_proc(gx_device_pdf * pdev, int w, int h, int x_width,
327
                    int y_offset, int x_offset, gs_id id, pdf_char_proc_t ** ppcp,
328
                    pdf_stream_position_t * ppos)
329
0
{
330
0
    gs_char char_code = 0;
331
0
    pdf_bitmap_fonts_t *const pbfs = pdev->text->bitmap_fonts;
332
0
    pdf_font_resource_t *font;
333
0
    pdf_resource_t *pres;
334
0
    pdf_char_proc_t *pcp;
335
0
    int code;
336
    /* This code added to store PCL bitmap glyphs in type 3 fonts where possible */
337
0
    gs_glyph glyph = GS_NO_GLYPH;
338
0
    gs_const_string *str = NULL;
339
0
    gs_show_enum *show_enum = (gs_show_enum *)pdev->pte;
340
0
    pdf_encoding_element_t *pet = 0;
341
    /* Since this is for text searching, its only useful if the character code
342
     * lies in an ASCII range, so we only handle some kinds of text layout.
343
     */
344
0
    int allowed_op = (show_enum->text.operation &
345
0
        (TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR));
346
347
    /* Check to see the current font is a type 3. We can get here if pdfwrite decides
348
     * it can't handle a font type, and renders to a bitmap instead. If that's the
349
     * case then we can't add the bitmap to the existing font (its not a type 3 font)
350
     * and must fall back to holding it in our fallback type 3 font 'collection'.
351
     */
352
    /* Because the bitmaps are stored directly in the cache they already have any
353
     * effects caused by non-identity FontMatrix entries applied. So if the type 3
354
     * font we created has a non-identity FontMatrix we can't use it and must
355
     * go back to collecting the bitmap into our fallback font.
356
     */
357
0
    if ((show_enum->current_font->FontType == ft_user_defined ||
358
0
        show_enum->current_font->FontType == ft_PDF_user_defined ||
359
0
        show_enum->current_font->FontType == ft_PCL_user_defined ||
360
0
        show_enum->current_font->FontType == ft_MicroType ||
361
0
        show_enum->current_font->FontType == ft_GL2_stick_user_defined ||
362
0
        show_enum->current_font->FontType == ft_GL2_531) && allowed_op &&
363
0
        show_enum->current_font->FontMatrix.xx == 1 && show_enum->current_font->FontMatrix.xy == 0 &&
364
0
        show_enum->current_font->FontMatrix.yx == 0 && show_enum->current_font->FontMatrix.yy == 1) {
365
0
        pdf_char_proc_ownership_t *pcpo;
366
367
0
        gs_font_base *base = (gs_font_base *)show_enum->current_font;
368
0
        code = pdf_attached_font_resource(pdev, show_enum->current_font, &font, NULL, NULL, NULL, NULL);
369
0
        if (code < 0)
370
0
            return code;
371
0
        if (font == NULL)
372
0
            return_error(gs_error_invalidfont);
373
374
        /* The text processing will have run past the glyph, so we need to 'back up'
375
         * by one and get it again in order to get the character code and glyph, and update
376
         * the pointer correctly.
377
         */
378
0
        show_enum->index--;
379
0
        code = gs_default_next_char_glyph((gs_text_enum_t *)show_enum, (gs_char *)&char_code, &glyph);
380
0
        if (code < 0)
381
0
            return code;
382
383
        /* If the returned character code is outside the possible Encoding for
384
         * a type 3 font, then set pet to NULL, this means we will fall back to
385
         * the 'collection' font, as pet is checked below.
386
         */
387
0
        if ((int)char_code >= 0 && (int)char_code <= 255) {
388
0
            pet = &font->u.simple.Encoding[char_code];
389
0
            if (pet) {
390
                /* Check to see if we *already* have this glyph in this font. If
391
                 * we do then we can't add it to this font. Setting pet to 0
392
                 * falls back to the collection method.
393
                 */
394
0
                for (pcpo = font->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
395
0
                    if (pcpo->glyph == pet->glyph && pcpo->char_code == char_code) {
396
0
                        pet = 0x00;
397
0
                        break;
398
0
                    }
399
0
                }
400
0
            }
401
0
        }
402
0
        else
403
0
            pet = 0x00;
404
405
        /* We need a glyph name for the type 3 font's Encoding, if we haven't got one
406
         * then we need to give up, something about the font or text is not acceptable
407
         * (see various comments above).
408
         */
409
0
        if (pet && pet->glyph != GS_NO_GLYPH && !(pet->str.size == 7 &&
410
0
            !strncmp((const char *)pet->str.data, ".notdef", 7))) {
411
0
            if (char_code < font->u.simple.FirstChar)
412
0
                font->u.simple.FirstChar = char_code;
413
0
            if ((int)char_code > font->u.simple.LastChar)
414
0
                font->u.simple.LastChar = char_code;
415
0
            base->FontBBox.q.x = max(base->FontBBox.q.x, w);
416
0
            base->FontBBox.q.y = max(base->FontBBox.q.y, y_offset + h);
417
0
            str = &pet->str;
418
0
            glyph = pet->glyph;
419
            /* This is to work around a weird Acrobat bug. If the Encoding of a type 3
420
             * (possibly other types) is simply a standard encoding (eg WinAnsiEncoding)
421
             * then Acrobat 4 & 8 just ignore the glyphs altogether. This forces us to write
422
             * all the used glyphs as /Differencess, and that makes it work <sigh>
423
             */
424
0
            pet->is_difference = 1;
425
0
            font->Widths[char_code] = psdf_round(pdev->char_width.x, 100, 10); /* See
426
                        pdf_write_Widths about rounding. We need to provide
427
                        a compatible data for Tj. */
428
0
        } else {
429
0
            char_code = assign_char_code(pdev, pdev->pte);
430
0
            font = pbfs->open_font; /* Type 3 */
431
0
        }
432
0
    } else {
433
0
        char_code = assign_char_code(pdev, pdev->pte);
434
0
        font = pbfs->open_font; /* Type 3 */
435
0
    }
436
437
0
    code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
438
0
    if (code < 0)
439
0
        return code;
440
0
    pcp = (pdf_char_proc_t *) pres;
441
0
    code = pdf_attach_charproc(pdev, font, pcp, glyph, char_code, str);
442
0
    if (code < 0)
443
0
        return code;
444
0
    pres->object->written = true;
445
0
    {
446
0
        stream *s = pdev->strm;
447
448
        /*
449
         * The resource file is positionable, so rather than use an
450
         * object reference for the length, we'll go back and fill it in
451
         * at the end of the definition.  Take 1M as the longest
452
         * definition we can handle.  (This used to be 10K, but there was
453
         * a real file that exceeded this limit.)
454
         */
455
0
        stream_puts(s, "<</Length       >>stream\n");
456
0
        ppos->start_pos = stell(s);
457
0
    }
458
0
    code = pdf_begin_encrypt(pdev, &pdev->strm, pres->object->id);
459
0
    if (code < 0)
460
0
        return code;
461
0
    pcp->y_offset = y_offset;
462
0
    pcp->x_offset = x_offset;
463
0
    font->u.simple.s.type3.FontBBox.q.x =
464
0
        max(font->u.simple.s.type3.FontBBox.q.x, w);
465
0
    font->u.simple.s.type3.FontBBox.q.y =
466
0
        max(font->u.simple.s.type3.FontBBox.q.y, y_offset + h);
467
0
    font->u.simple.s.type3.max_y_offset =
468
0
        max(font->u.simple.s.type3.max_y_offset, h + (h >> 2));
469
0
    pcp->real_width.x = w;
470
0
    pcp->real_width.y = y_offset + h;
471
0
    *ppcp = pcp;
472
0
    return 0;
473
0
}
474
475
/* End a CharProc. */
476
int
477
pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos)
478
0
{
479
0
    stream *s;
480
0
    gs_offset_t start_pos, end_pos, length;
481
482
0
    if (pdf_end_encrypt(pdev))
483
0
        s_close_filters(&pdev->strm, pdev->strm->strm);
484
485
0
    s = pdev->strm;
486
0
    start_pos = ppos->start_pos;
487
0
    end_pos = stell(s);
488
0
    length = end_pos - start_pos;
489
0
    if (length > 999999)
490
0
        return_error(gs_error_limitcheck);
491
0
    sseek(s, start_pos - 15);
492
0
    pprintd1(s, "%d", length);
493
0
    sseek(s, end_pos);
494
0
    if (pdev->PDFA != 0)
495
0
        stream_puts(s, "\n");
496
0
    stream_puts(s, "endstream\n");
497
0
    pdf_end_separate(pdev, resourceCharProc);
498
0
    return 0;
499
0
}
500
501
/* Mark glyph names for garbager. */
502
void
503
pdf_mark_glyph_names(const pdf_font_resource_t *pdfont, const gs_memory_t *memory)
504
0
{
505
0
    if (pdfont->mark_glyph == NULL) {
506
        /* Synthesised bitmap fonts pass here. */
507
0
        return;
508
0
    }
509
0
    if (pdfont->u.simple.Encoding != NULL) {
510
0
         int i;
511
512
0
         for (i = 0; i < 256; i++)
513
0
             if (pdfont->u.simple.Encoding[i].glyph != GS_NO_GLYPH)
514
0
                pdfont->mark_glyph(memory, pdfont->u.simple.Encoding[i].glyph, pdfont->mark_glyph_data);
515
0
     }
516
0
    if (pdfont->FontType == ft_user_defined ||
517
0
        pdfont->FontType == ft_PDF_user_defined ||
518
0
        pdfont->FontType == ft_PCL_user_defined ||
519
0
        pdfont->FontType == ft_MicroType ||
520
0
        pdfont->FontType == ft_GL2_stick_user_defined ||
521
0
        pdfont->FontType == ft_GL2_531) {
522
0
        const pdf_char_proc_ownership_t *pcpo = pdfont->u.simple.s.type3.char_procs;
523
524
0
        for (; pcpo != NULL; pcpo = pcpo->font_next)
525
0
            pdfont->mark_glyph(memory, pcpo->glyph, pdfont->mark_glyph_data);
526
0
    }
527
0
}
528
529
/* Put out a reference to an image as a character in a synthesized font. */
530
int
531
pdf_do_char_image(gx_device_pdf * pdev, const pdf_char_proc_t * pcp,
532
                  const gs_matrix * pimat)
533
0
{
534
    /* We need to choose a font, which use the charproc.
535
       In most cases it is the last font, which the charproc is attached to.
536
       If the charproc is substituted, it causes a font change. */
537
0
    const pdf_char_proc_ownership_t * pcpo = pcp->owner_fonts;
538
0
    pdf_font_resource_t *pdfont = pcpo->font;
539
0
    byte ch = pcpo->char_code;
540
0
    pdf_text_state_values_t values;
541
542
0
    values.character_spacing = 0;
543
0
    values.pdfont = pdfont;
544
0
    values.size = 1;
545
0
    values.matrix = *pimat;
546
0
    values.render_mode = pdev->pte->pgs->text_rendering_mode;
547
0
    values.word_spacing = 0;
548
0
    pdf_set_text_state_values(pdev, &values);
549
0
    pdf_bitmap_char_update_bbox(pdev, pcp->x_offset, pcp->y_offset, pcp->real_width.x, pcp->real_width.y);
550
0
    pdf_append_chars(pdev, &ch, 1, pdfont->Widths[ch] * pimat->xx, 0.0, false);
551
0
    return 0;
552
0
}
553
554
/*
555
 * Write the Encoding for bitmap fonts, if needed.
556
 */
557
int
558
pdf_write_bitmap_fonts_Encoding(gx_device_pdf *pdev)
559
0
{
560
0
    pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
561
562
0
    if (pbfs->bitmap_encoding_id) {
563
0
        stream *s;
564
0
        int i;
565
566
0
        pdf_open_separate(pdev, pbfs->bitmap_encoding_id, resourceEncoding);
567
0
        s = pdev->strm;
568
        /*
569
         * Even though the PDF reference documentation says that a
570
         * BaseEncoding key is required unless the encoding is
571
         * "based on the base font's encoding" (and there is no base
572
         * font in this case), Acrobat 2.1 gives an error if the
573
         * BaseEncoding key is present.
574
         */
575
0
        stream_puts(s, "<</Type/Encoding/Differences[0");
576
0
        for (i = 0; i <= pbfs->max_embedded_code; ++i) {
577
0
            if (!(i & 15))
578
0
                stream_puts(s, "\n");
579
0
            pprintd1(s, "/a%d", i);
580
0
        }
581
0
        stream_puts(s, "\n] >>\n");
582
0
        pdf_end_separate(pdev, resourceEncoding);
583
0
        pbfs->bitmap_encoding_id = 0;
584
0
    }
585
0
    return 0;
586
0
}
587
588
/*
589
 * Start charproc accumulation for a Type 3 font.
590
 */
591
int
592
pdf_start_charproc_accum(gx_device_pdf *pdev)
593
0
{
594
0
    pdf_char_proc_t *pcp;
595
0
    pdf_resource_t *pres;
596
0
    int id = gs_next_ids(pdev->memory, 1);
597
0
    int code = pdf_enter_substream(pdev, resourceCharProc, id,
598
0
                                   &pres, false, pdev->CompressFonts);
599
600
0
    if (code < 0)
601
0
       return code;
602
0
    pres->rid = id;
603
0
    pcp = (pdf_char_proc_t *)pres;
604
0
    pcp->owner_fonts = NULL;
605
0
    return 0;
606
0
}
607
608
/*
609
 * Install charproc accumulator for a Type 3 font.
610
 */
611
int
612
pdf_set_charproc_attrs(gx_device_pdf *pdev, gs_font *font, double *pw, int narg,
613
                gs_text_cache_control_t control, gs_char ch, bool scale_100)
614
0
{
615
0
    pdf_font_resource_t *pdfont;
616
0
    pdf_resource_t *pres = pdev->accumulating_substream_resource;
617
0
    pdf_char_proc_t *pcp;
618
0
    int code;
619
620
0
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
621
0
    if (code < 0)
622
0
        return code;
623
0
    pcp = (pdf_char_proc_t *)pres;
624
0
    pcp->owner_fonts = NULL;
625
0
    pcp->real_width.x = pw[font->WMode && narg > 6 ? 6 : 0];
626
0
    pcp->real_width.y = pw[font->WMode && narg > 6 ? 7 : 1];
627
0
    pcp->v.x = (narg > 8 ? pw[8] : 0);
628
0
    pcp->v.y = (narg > 8 ? pw[9] : 0);
629
0
    if (control == TEXT_SET_CHAR_WIDTH) {
630
        /* PLRM 5.7.1 "BuildGlyph" reads : "Normally, it is unnecessary and
631
        undesirable to initialize the current color parameter, because show
632
        is defined to paint glyphs with the current color."
633
        However comparefiles/Bug687044.ps doesn't follow that. */
634
0
        pdev->skip_colors = false;
635
0
        pprintg1(pdev->strm, "%g 0 d0\n", (float)pw[0]);
636
        /* The colour change described above can't affect PCL fonts and we need
637
         * all glyphs to be noted as cached in order for the bitmap font cache
638
         * probing to work properly.
639
         */
640
0
        if (font->FontType == ft_PCL_user_defined || font->FontType == ft_GL2_stick_user_defined
641
0
            || font->FontType == ft_GL2_531 || font->FontType == ft_MicroType)
642
0
            pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
643
0
    } else {
644
0
        double d;
645
0
        pdev->skip_colors = true;
646
0
        if (pw[4] < pw[2]) {
647
0
            d = pw[2];
648
0
            pw[2] = pw[4];
649
0
            pw[4] = d;
650
0
        }
651
0
        if (pw[5] < pw[3]) {
652
0
            d = pw[5];
653
0
            pw[5] = pw[3];
654
0
            pw[3] = d;
655
0
        }
656
0
        pprintg6(pdev->strm, "%g %g %g %g %g %g d1\n",
657
0
            (float)pw[0], (float)0.0, (float)pw[2],
658
0
            (float)pw[3], (float)pw[4], (float)pw[5]);
659
0
        pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
660
0
    }
661
    /* See comments in pdf_text_process regarding type 3 CharProc accumulation
662
     * Initially this matrix was emitted there, at the start of the accumulator
663
     * but if we do that then GS incorrectly applied the matrix to the 'd1'
664
     * operator. We write the scale matrix here because this is *after* the
665
     * 'd1' has been emitted above, and so does not affect it.
666
     */
667
0
    if (scale_100) {
668
0
    code = stream_puts(pdev->strm, "0.01 0 0 0.01 0 0 cm\n");
669
0
    if (code < 0)
670
0
        return code;
671
0
    }
672
0
    return 0;
673
0
}
674
675
/*
676
 * Open a stream object in the temporary file.
677
 */
678
679
int
680
pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype,
681
        gs_id id, pdf_resource_t **ppres, bool reserve_object_id, int options)
682
0
{
683
0
    int code;
684
0
    pdf_resource_t *pres;
685
0
    stream *s, *save_strm = pdev->strm;
686
0
    pdf_data_writer_t writer;
687
0
    static const pdf_filter_names_t fnames = {
688
0
        PDF_FILTER_NAMES
689
0
    };
690
691
0
    pdev->streams.save_strm = pdev->strm;
692
693
0
    if (rtype >= NUM_RESOURCE_TYPES)
694
0
        rtype = resourceOther;
695
0
    code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id),
696
0
                pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1);
697
0
    if (code < 0)
698
0
        return code;
699
0
    cos_become(pres->object, cos_type_stream);
700
0
    s = cos_write_stream_alloc((cos_stream_t *)pres->object, pdev, "pdf_enter_substream");
701
0
    if (s == 0)
702
0
        return_error(gs_error_VMerror);
703
0
    pdev->strm = s;
704
0
    code = pdf_append_data_stream_filters(pdev, &writer,
705
0
                             options | DATA_STREAM_NOLENGTH, pres->object->id);
706
0
    if (code < 0) {
707
0
        pdev->strm = save_strm;
708
0
        return code;
709
0
    }
710
0
    code = pdf_put_filters((cos_dict_t *)pres->object, pdev, writer.binary.strm, &fnames);
711
0
    if (code < 0) {
712
0
        pdev->strm = save_strm;
713
0
        return code;
714
0
    }
715
0
    pdev->strm = writer.binary.strm;
716
0
    *ppres = pres;
717
0
    return 0;
718
0
}
719
720
/*
721
 * Close a stream object in the temporary file.
722
 */
723
int
724
pdf_close_aside(gx_device_pdf *pdev)
725
0
{
726
    /* We should call pdf_end_data here, but we don't want to put pdf_data_writer_t
727
       into pdf_substream_save stack to simplify garbager descriptors.
728
       Use a lower level functions instead that. */
729
0
    stream *s = pdev->strm;
730
0
    cos_stream_t *pcs = cos_stream_from_pipeline(s);
731
0
    int status = s_close_filters(&s, NULL);
732
733
0
    pdev->strm = pdev->streams.save_strm;
734
0
    if (status < 0)
735
0
         return(gs_note_error(gs_error_ioerror));
736
737
0
    if (!pcs)
738
0
        return gs_note_error(gs_error_ioerror);
739
740
0
    pcs->is_open = false;
741
0
    return 0;
742
0
}
743
744
/*
745
 * Enter the substream accumulation mode.
746
 */
747
int
748
pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype,
749
        gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress)
750
0
{
751
0
    int sbstack_ptr = pdev->sbstack_depth;
752
0
    pdf_resource_t *pres;
753
0
    stream *save_strm = pdev->strm;
754
0
    int code;
755
756
0
    if (pdev->sbstack_depth >= pdev->sbstack_size)
757
0
        return_error(gs_error_unregistered); /* Must not happen. */
758
0
    if (pdev->sbstack[sbstack_ptr].text_state == 0) {
759
0
        pdev->sbstack[sbstack_ptr].text_state = pdf_text_state_alloc(pdev->pdf_memory);
760
0
        if (pdev->sbstack[sbstack_ptr].text_state == 0)
761
0
            return_error(gs_error_VMerror);
762
0
    }
763
0
    code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id,
764
0
                    (compress ? DATA_STREAM_COMPRESS : 0));
765
0
    if (code < 0)
766
0
        return code;
767
0
    code = pdf_save_viewer_state(pdev, NULL);
768
0
    if (code < 0) {
769
0
        pdev->strm = save_strm;
770
0
        return code;
771
0
    }
772
0
    pdev->sbstack[sbstack_ptr].context = pdev->context;
773
0
    pdf_text_state_copy(pdev->sbstack[sbstack_ptr].text_state, pdev->text->text_state);
774
0
    pdf_set_text_state_default(pdev->text->text_state);
775
0
    pdev->sbstack[sbstack_ptr].clip_path = pdev->clip_path;
776
0
    pdev->clip_path = 0;
777
0
    pdev->sbstack[sbstack_ptr].clip_path_id = pdev->clip_path_id;
778
0
    pdev->clip_path_id = pdev->no_clip_path_id;
779
0
    pdev->sbstack[sbstack_ptr].vgstack_bottom = pdev->vgstack_bottom;
780
0
    pdev->vgstack_bottom = pdev->vgstack_depth;
781
0
    pdev->sbstack[sbstack_ptr].strm = save_strm;
782
0
    pdev->sbstack[sbstack_ptr].procsets = pdev->procsets;
783
0
    pdev->sbstack[sbstack_ptr].substream_Resources = pdev->substream_Resources;
784
0
    pdev->sbstack[sbstack_ptr].skip_colors = pdev->skip_colors;
785
0
    pdev->sbstack[sbstack_ptr].font3 = pdev->font3;
786
0
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = pdev->accumulating_substream_resource;
787
0
    pdev->sbstack[sbstack_ptr].charproc_just_accumulated = pdev->charproc_just_accumulated;
788
0
    pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object;
789
0
    pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict;
790
0
    pdev->sbstack[sbstack_ptr].objname = pdev->objname;
791
0
    pdev->sbstack[sbstack_ptr].last_charpath_op = pdev->last_charpath_op;
792
0
    pdev->skip_colors = false;
793
0
    pdev->charproc_just_accumulated = false;
794
0
    pdev->pres_soft_mask_dict = NULL;
795
0
    pdev->objname.data = NULL;
796
0
    pdev->objname.size = 0;
797
    /* Do not reset pdev->accumulating_a_global_object - it inherits. */
798
0
    pdev->sbstack_depth++;
799
0
    pdev->procsets = 0;
800
0
    pdev->font3 = 0;
801
0
    pdev->context = PDF_IN_STREAM;
802
0
    pdev->accumulating_substream_resource = pres;
803
0
    pdev->last_charpath_op = 0;
804
    /* Do not alter type3charpath, inherit the current value. We need to know if */
805
    /* we are inside a charpath operation, and only reset this when the charpath */
806
    /* is complete */
807
0
    if (rtype != resourceXObject)
808
0
        pdf_reset_graphics(pdev);
809
0
    else {
810
0
        if (pdev->vg_initial_set)
811
0
            pdev->state.blend_mode = pdev->vg_initial.blend_mode;
812
0
    }
813
0
    *ppres = pres;
814
0
    return 0;
815
0
}
816
817
/*
818
 * Exit the substream accumulation mode.
819
 */
820
int
821
pdf_exit_substream(gx_device_pdf *pdev)
822
0
{
823
0
    int code, code1;
824
0
    int sbstack_ptr;
825
826
0
    if (pdev->sbstack_depth <= 0)
827
0
        return_error(gs_error_unregistered); /* Must not happen. */
828
0
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
829
0
    sbstack_ptr = pdev->sbstack_depth - 1;
830
0
    while (pdev->vgstack_depth > pdev->vgstack_bottom) {
831
0
        code1 = pdf_restore_viewer_state(pdev, pdev->strm);
832
0
        if (code >= 0)
833
0
            code = code1;
834
0
    }
835
0
    if (pdev->clip_path != 0)
836
0
        gx_path_free(pdev->clip_path, "pdf_end_charproc_accum");
837
0
    code1 = pdf_close_aside(pdev);
838
0
    if (code1 < 0 && code >= 0)
839
0
        code = code1;
840
0
    pdev->context = pdev->sbstack[sbstack_ptr].context;
841
0
    pdf_text_state_copy(pdev->text->text_state, pdev->sbstack[sbstack_ptr].text_state);
842
0
    gs_free_object(pdev->pdf_memory, pdev->sbstack[sbstack_ptr].text_state, "free text state for stream");
843
0
    pdev->sbstack[sbstack_ptr].text_state = 0;
844
0
    pdev->clip_path = pdev->sbstack[sbstack_ptr].clip_path;
845
0
    pdev->sbstack[sbstack_ptr].clip_path = 0;
846
0
    pdev->clip_path_id = pdev->sbstack[sbstack_ptr].clip_path_id;
847
0
    pdev->vgstack_bottom = pdev->sbstack[sbstack_ptr].vgstack_bottom;
848
0
    pdev->strm = pdev->sbstack[sbstack_ptr].strm;
849
0
    pdev->sbstack[sbstack_ptr].strm = 0;
850
0
    pdev->procsets = pdev->sbstack[sbstack_ptr].procsets;
851
0
    pdev->substream_Resources = pdev->sbstack[sbstack_ptr].substream_Resources;
852
0
    pdev->sbstack[sbstack_ptr].substream_Resources = 0;
853
0
    pdev->skip_colors = pdev->sbstack[sbstack_ptr].skip_colors;
854
0
    pdev->font3 = pdev->sbstack[sbstack_ptr].font3;
855
0
    pdev->sbstack[sbstack_ptr].font3 = 0;
856
0
    pdev->accumulating_substream_resource = pdev->sbstack[sbstack_ptr].accumulating_substream_resource;
857
0
    pdev->sbstack[sbstack_ptr].accumulating_substream_resource = 0;
858
0
    pdev->charproc_just_accumulated = pdev->sbstack[sbstack_ptr].charproc_just_accumulated;
859
0
    pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object;
860
0
    pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict;
861
0
    pdev->objname = pdev->sbstack[sbstack_ptr].objname;
862
0
    pdev->last_charpath_op = pdev->sbstack[sbstack_ptr].last_charpath_op;
863
0
    pdev->sbstack_depth = sbstack_ptr;
864
0
    code1 = pdf_restore_viewer_state(pdev, NULL);
865
0
    if (code1 < 0 && code >= 0)
866
0
        code = code1;
867
0
    return code;
868
0
}
869
870
static bool
871
pdf_is_same_charproc_attrs1(gx_device_pdf *pdev, pdf_char_proc_t *pcp0, pdf_char_proc_t *pcp1)
872
0
{
873
0
    if (pcp0->real_width.x != pcp1->real_width.x)
874
0
        return false;
875
0
    if (pcp0->real_width.y != pcp1->real_width.y)
876
0
        return false;
877
0
    if (pcp0->v.x != pcp1->v.x)
878
0
        return false;
879
0
    if (pcp0->v.y != pcp1->v.y)
880
0
        return false;
881
0
    return true;
882
0
}
883
884
typedef struct charproc_compatibility_data_s {
885
    const pdf_char_glyph_pairs_t *cgp;
886
    pdf_font_resource_t *pdfont;
887
    gs_char char_code;
888
    gs_glyph glyph;
889
    gs_font *font;
890
} charproc_compatibility_data_t;
891
892
static bool
893
is_char_code_used(pdf_font_resource_t *pdfont, gs_char char_code)
894
0
{
895
0
    pdf_char_proc_ownership_t *pcpo;
896
897
0
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
898
0
        if (pcpo->char_code == char_code) {
899
0
            return true;
900
0
        }
901
0
    }
902
0
    return false;
903
0
}
904
905
static int
906
pdf_is_charproc_compatible(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
907
0
{
908
0
    charproc_compatibility_data_t *data = (charproc_compatibility_data_t *)pdev->find_resource_param;
909
0
    pdf_char_proc_t *pcp0 = (pdf_char_proc_t *)pres0;
910
0
    pdf_char_proc_t *pcp1 = (pdf_char_proc_t *)pres1;
911
0
    pdf_font_resource_t *pdfont = data->pdfont;
912
0
    pdf_char_proc_ownership_t *pcpo;
913
0
    pdf_font_cache_elem_t **e;
914
0
    bool can_add_to_current_font = false, computed_can_add_to_current_font = false;
915
916
    /* Does it have same attributes ? */
917
0
    if (!pdf_is_same_charproc_attrs1(pdev, pcp0, pcp1))
918
0
        return 0;
919
    /* Is it from same font ? */
920
0
    for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
921
0
        if (pdfont == pcpo->font) {
922
            /* Check for encoding conflict. */
923
0
            if (pcpo->char_code == data->char_code && pcpo->glyph == data->glyph)
924
0
                return 1; /* Same char code. */
925
0
            if (!computed_can_add_to_current_font) {
926
0
                can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
927
0
                computed_can_add_to_current_font = true;
928
0
            }
929
0
            if (can_add_to_current_font)
930
0
                return 1; /* No conflict. */
931
0
        }
932
0
    }
933
    /* Look for another font with same encoding,
934
       because we want to reduce the number of new fonts.
935
       We also restrict with ones attached to same PS font,
936
       otherwise it creates too mixed fonts and disturbs word breaks.
937
     */
938
0
    e = pdf_locate_font_cache_elem(pdev, data->font);
939
0
    if (e != NULL) {
940
0
        for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
941
0
            if (pcpo->char_code != data->char_code || pcpo->glyph != data->glyph)
942
0
                continue; /* Need same Encoding to generate a proper ToUnicode. */
943
0
            if (pdfont->u.simple.s.type3.bitmap_font != pcpo->font->u.simple.s.type3.bitmap_font)
944
0
                continue;
945
0
            if (gs_matrix_compare(&pdfont->u.simple.s.type3.FontMatrix, &pcpo->font->u.simple.s.type3.FontMatrix))
946
0
                continue;
947
0
            if (data->cgp != NULL) {
948
0
                if (!pdf_check_encoding_compatibility(pcpo->font, data->cgp->s, data->cgp->num_all_chars))
949
0
                    continue;
950
0
            }
951
0
            if ((*e)->pdfont != pcpo->font)
952
0
                continue;
953
0
            data->pdfont = pcpo->font; /* Switch to the other font. */
954
0
            return 1;
955
0
        }
956
0
    }
957
    /* Check whether it can be added into the current font. */
958
0
    if (!computed_can_add_to_current_font)
959
0
        can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
960
0
    if (!can_add_to_current_font) {
961
        /* Can't substitute due to encoding conflict. */
962
0
        return 0;
963
0
    }
964
    /* The current font will share it with another font. */
965
0
    return 1;
966
0
}
967
968
static int
969
pdf_find_same_charproc_aux(gx_device_pdf *pdev,
970
            pdf_font_resource_t **ppdfont, pdf_char_proc_t **ppcp)
971
0
{
972
0
    pdf_char_proc_ownership_t *pcpo;
973
0
    int code;
974
975
    /* fixme: this passes parameters to pdf_is_charproc_compatible
976
       through special gx_device_pdf field pdev->find_resource_param
977
       due to prototype limitation of pdf_find_same_resource.
978
       It would be better to change the client data argument type in there to void. */
979
0
    for (pcpo = (*ppdfont)->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
980
0
        pdf_char_proc_t *pcp = pcpo->char_proc;
981
982
0
        if (*ppcp != pcp && pdf_is_same_charproc_attrs1(pdev, *ppcp, pcp)) {
983
0
            cos_object_t *pco0 = pcp->object;
984
0
            cos_object_t *pco1 = (*ppcp)->object;
985
986
0
            code = pco0->cos_procs->equal(pco0, pco1, pdev);
987
0
            if (code < 0) {
988
0
                return code;
989
0
            }
990
0
            if (code) {
991
0
                *ppcp = pcp;
992
0
                return 1;
993
0
            }
994
0
        }
995
0
    }
996
0
    return pdf_find_same_resource(pdev, resourceCharProc, (pdf_resource_t **)ppcp, pdf_is_charproc_compatible);
997
0
}
998
static int
999
pdf_find_same_charproc(gx_device_pdf *pdev,
1000
            pdf_font_resource_t **ppdfont, const pdf_char_glyph_pairs_t *cgp,
1001
            pdf_char_proc_t **ppcp, gs_glyph glyph, gs_char char_code,
1002
            gs_font *font)
1003
0
{
1004
0
    charproc_compatibility_data_t data;
1005
0
    int code;
1006
1007
0
    data.cgp = cgp;
1008
0
    data.pdfont = *ppdfont;
1009
0
    data.char_code = char_code;
1010
0
    data.glyph = glyph;
1011
0
    data.font = font;
1012
0
    pdev->find_resource_param = &data;
1013
0
    code = pdf_find_same_charproc_aux(pdev, ppdfont, ppcp);
1014
0
    pdev->find_resource_param = NULL;
1015
0
    *ppdfont = data.pdfont;
1016
0
    return code;
1017
0
}
1018
1019
static bool
1020
pdf_is_charproc_defined(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, gs_char ch)
1021
0
{
1022
0
    pdf_char_proc_ownership_t *pcpo;
1023
1024
0
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
1025
0
        if (pcpo->char_code == ch)
1026
0
            return true;
1027
0
    }
1028
0
    return false;
1029
0
}
1030
1031
static int
1032
complete_adding_char(gx_device_pdf *pdev, gs_font *font,
1033
                     gs_glyph glyph, gs_char ch, pdf_char_proc_t *pcp,
1034
                     const gs_const_string *gnstr)
1035
0
{
1036
0
    pdf_font_resource_t *pdfont;
1037
0
    double *real_widths;
1038
0
    byte *glyph_usage;
1039
0
    int char_cache_size, width_cache_size;
1040
0
    pdf_encoding_element_t *pet;
1041
0
    int code;
1042
1043
0
    code = pdf_attached_font_resource(pdev, font, &pdfont,
1044
0
                &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1045
0
    if (code < 0)
1046
0
        return code;
1047
0
    code = pdf_attach_charproc(pdev, pdfont, pcp, glyph, ch, gnstr);
1048
0
    if (code < 0)
1049
0
        return code;
1050
0
    if (ch >= char_cache_size || ch >= width_cache_size)
1051
0
        return_error(gs_error_unregistered); /* Must not happen. */
1052
0
    pet = &pdfont->u.simple.Encoding[ch];
1053
0
    pdfont->Widths[ch] = pcp->real_width.x;
1054
0
    real_widths[ch * 2    ] = pcp->real_width.x;
1055
0
    real_widths[ch * 2 + 1] = pcp->real_width.y;
1056
0
    glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
1057
0
    pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
1058
0
    if (pdfont->u.simple.v != NULL && font->WMode) {
1059
0
        pdfont->u.simple.v[ch].x = pcp->v.x;
1060
0
        pdfont->u.simple.v[ch].y = pcp->v.x;
1061
0
    }
1062
0
    pet->glyph = glyph;
1063
0
    pet->str = *gnstr;
1064
0
    pet->is_difference = true;
1065
0
    if (pdfont->u.simple.LastChar < (int)ch)
1066
0
        pdfont->u.simple.LastChar = (int)ch;
1067
0
    if (pdfont->u.simple.FirstChar > (int)ch)
1068
0
        pdfont->u.simple.FirstChar = (int)ch;
1069
0
    return 0;
1070
0
}
1071
1072
static int
1073
pdf_char_widths_from_charprocs(gx_device_pdf *pdev, gs_font *font)
1074
0
{
1075
0
    pdf_font_resource_t *pdfont;
1076
0
    double *real_widths;
1077
0
    byte *glyph_usage;
1078
0
    int char_cache_size, width_cache_size;
1079
0
    pdf_char_proc_ownership_t *pcpo;
1080
0
    int code;
1081
1082
0
    code = pdf_attached_font_resource(pdev, font, &pdfont,
1083
0
                &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
1084
0
    if (code < 0)
1085
0
        return code;
1086
0
    for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
1087
0
        pdf_char_proc_t *pcp = pcpo->char_proc;
1088
0
        gs_char ch = pcpo->char_code;
1089
1090
0
        real_widths[ch * 2    ] = pcp->real_width.x;
1091
0
        real_widths[ch * 2 + 1] = pcp->real_width.y;
1092
0
        glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
1093
0
    }
1094
0
    return 0;
1095
0
}
1096
1097
/*
1098
 * Complete charproc accumulation for a Type 3 font.
1099
 */
1100
int
1101
pdf_end_charproc_accum(gx_device_pdf *pdev, gs_font *font, const pdf_char_glyph_pairs_t *cgp,
1102
                       gs_glyph glyph, gs_char output_char_code, const gs_const_string *gnstr)
1103
0
{
1104
0
    int code;
1105
0
    pdf_resource_t *pres = (pdf_resource_t *)pdev->accumulating_substream_resource;
1106
    /* We could use pdfont->u.simple.s.type3.char_procs insted the thing above
1107
       unless the font is defined recursively.
1108
       But we don't want such assumption. */
1109
0
    pdf_char_proc_t *pcp = (pdf_char_proc_t *)pres;
1110
0
    pdf_font_resource_t *pdfont;
1111
0
    gs_char ch = output_char_code;
1112
0
    bool checking_glyph_variation = false;
1113
1114
0
    if (ch == GS_NO_CHAR)
1115
0
        return_error(gs_error_unregistered); /* Must not happen. */
1116
0
    if (ch >= 256)
1117
0
        return_error(gs_error_unregistered); /* Must not happen. */
1118
0
    code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
1119
0
    if (code < 0)
1120
0
        return code;
1121
0
    if (pdfont != (pdf_font_resource_t *)pdev->font3)
1122
0
        return_error(gs_error_unregistered); /* Must not happen. */
1123
0
    code = pdf_exit_substream(pdev);
1124
0
    if (code < 0)
1125
0
        return code;
1126
0
    if (!(pdfont->used[ch >> 3] & (0x80 >> (ch & 7))) ||
1127
0
        !(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) {
1128
        /* First appearence or not cached - check for duplicates. */
1129
0
        pdf_font_resource_t *pdfont1 = pdfont;
1130
1131
0
        checking_glyph_variation = true;
1132
        /* CAUTION : a possible font change. */
1133
0
        code = pdf_find_same_charproc(pdev, &pdfont, cgp, &pcp, glyph, ch, font);
1134
0
        if (code < 0)
1135
0
            return code;
1136
0
        if (code != 0) {
1137
0
            code = pdf_cancel_resource(pdev, pres, resourceCharProc);
1138
0
            if (code < 0)
1139
0
                return code;
1140
0
            pdf_forget_resource(pdev, pres, resourceCharProc);
1141
0
            if (pdfont1 != pdfont) {
1142
0
                code = pdf_attach_font_resource(pdev, font, pdfont);
1143
0
                if (code < 0)
1144
0
                    return code;
1145
0
                code = pdf_char_widths_from_charprocs(pdev, font);
1146
0
                if (code < 0)
1147
0
                    return code;
1148
0
            }
1149
0
            pdev->charproc_just_accumulated = true;
1150
0
            return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
1151
0
        }
1152
0
        if (pdf_is_charproc_defined(pdev, pdfont, ch)) {
1153
            /* Encoding conflict after a font change. */
1154
0
            gs_font *base_font = font, *below;
1155
1156
0
            while ((below = base_font->base) != base_font &&
1157
0
                    base_font->procs.same_font(base_font, below, FONT_SAME_OUTLINES))
1158
0
                base_font = below;
1159
0
            code = pdf_make_font3_resource(pdev, base_font, &pdfont);
1160
0
            if (code < 0)
1161
0
                return code;
1162
0
            code = pdf_attach_font_resource(pdev, font, pdfont);
1163
0
            if (code < 0)
1164
0
                return code;
1165
0
        }
1166
0
    }
1167
0
    pdf_reserve_object_id(pdev, pres, 0);
1168
0
    if (checking_glyph_variation)
1169
0
        pdev->charproc_just_accumulated = true;
1170
0
    return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
1171
0
}
1172
1173
/* Add procsets to substream Resources. */
1174
int
1175
pdf_add_procsets(cos_dict_t *pcd, pdf_procset_t procsets)
1176
0
{
1177
0
    char str[5 + 7 + 7 + 7 + 5 + 2];
1178
0
    cos_value_t v;
1179
1180
0
    strcpy(str, "[/PDF");
1181
0
    if (procsets & ImageB)
1182
0
        strcat(str, "/ImageB");
1183
0
    if (procsets & ImageC)
1184
0
        strcat(str, "/ImageC");
1185
0
    if (procsets & ImageI)
1186
0
        strcat(str, "/ImageI");
1187
0
    if (procsets & Text)
1188
0
        strcat(str, "/Text");
1189
0
    strcat(str, "]");
1190
0
    cos_string_value(&v, (byte *)str, strlen(str));
1191
0
    return cos_dict_put_c_key(pcd, "/ProcSet", &v);
1192
0
}
1193
1194
/* Add a resource to substream Resources. */
1195
int
1196
pdf_add_resource(gx_device_pdf *pdev, cos_dict_t *pcd, const char *key, pdf_resource_t *pres)
1197
0
{
1198
0
    if (pcd != 0) {
1199
0
        const cos_value_t *v = cos_dict_find(pcd, (const byte *)key, strlen(key));
1200
0
        cos_dict_t *list;
1201
0
        int code;
1202
0
        char buf[10 + (sizeof(long) * 8 / 3 + 1)], buf1[sizeof(pres->rname) + 1];
1203
1204
0
        if (pdev->ForOPDFRead && !pres->global && pdev->accumulating_a_global_object) {
1205
0
            pres->global = true;
1206
0
            code = cos_dict_put_c_key_bool((cos_dict_t *)pres->object, "/.Global", true);
1207
0
            if (code < 0)
1208
0
                return code;
1209
0
        }
1210
0
        gs_sprintf(buf, "%ld 0 R\n", pres->object->id);
1211
0
        if (v != NULL) {
1212
0
            if (v->value_type != COS_VALUE_OBJECT &&
1213
0
                v->value_type != COS_VALUE_RESOURCE)
1214
0
                return_error(gs_error_unregistered); /* Must not happen. */
1215
0
            list = (cos_dict_t *)v->contents.object;
1216
0
            if (list->cos_procs != &cos_dict_procs)
1217
0
                return_error(gs_error_unregistered); /* Must not happen. */
1218
0
        } else {
1219
0
            list = cos_dict_alloc(pdev, "pdf_add_resource");
1220
0
            if (list == NULL)
1221
0
                return_error(gs_error_VMerror);
1222
0
            code = cos_dict_put_c_key_object((cos_dict_t *)pcd, key, (cos_object_t *)list);
1223
0
            if (code < 0)
1224
0
                return code;
1225
0
        }
1226
0
        buf1[0] = '/';
1227
0
        strcpy(buf1 + 1, pres->rname);
1228
0
        return cos_dict_put_string(list, (const byte *)buf1, strlen(buf1),
1229
0
                        (const byte *)buf, strlen(buf));
1230
0
    }
1231
0
    return 0;
1232
0
}