Coverage Report

Created: 2025-06-10 07:27

/src/ghostpdl/devices/vector/gdevpdtw.c
Line
Count
Source (jump to first uncovered line)
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
/* Font resource writing for pdfwrite text */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gxfcmap.h"
22
#include "gxfont.h"
23
#include "gxfcopy.h"
24
#include "gscencs.h"
25
#include "gdevpsf.h"
26
#include "gdevpdfx.h"
27
#include "gdevpdfo.h"   /* for object->written */
28
#include "gdevpdtd.h"   /* for writing FontDescriptor */
29
#include "gdevpdtf.h"
30
#include "gdevpdti.h"   /* for writing bitmap fonts Encoding */
31
#include "gdevpdtw.h"
32
#include "gdevpdtv.h"
33
#include "sarc4.h"
34
35
static const char *const encoding_names[] = {
36
    KNOWN_REAL_ENCODING_NAMES
37
};
38
39
/* ================ Font resource writing ================ */
40
41
/* ---------------- Private ---------------- */
42
43
/* Write the Widths for a font. */
44
static int
45
pdf_write_Widths(gx_device_pdf *pdev, int first, int last, const double *widths)
46
30.1k
{
47
30.1k
    stream *s = pdev->strm;
48
30.1k
    int i;
49
50
30.1k
    if (first > last)
51
0
        first = last = 0;
52
30.1k
    pprintd2(s, "/FirstChar %d/LastChar %d/Widths[", first, last);
53
2.24M
    for (i = first; i <= last; ++i)
54
2.21M
        pprintg1(s, (i & 15 ? " %g" : "\n%g"), psdf_round(widths[i], 100, 10));
55
30.1k
    stream_puts(s, "]\n");
56
30.1k
    return 0;
57
30.1k
}
58
59
/* Check strings equality. */
60
static bool
61
strings_equal(const gs_const_string *str0, const gs_const_string *str1)
62
667k
{
63
667k
    return str0->size == str1->size &&
64
667k
           !memcmp(str0->data, str1->data, str0->size);
65
667k
}
66
67
/* Check if an encoding element differs from a standard one. */
68
static int
69
pdf_different_encoding_element(const pdf_font_resource_t *pdfont, int ch, int encoding_index)
70
8.16M
{
71
8.16M
    if (pdfont->u.simple.Encoding[ch].is_difference)
72
29.0k
        return 1;
73
8.13M
    else if (encoding_index != ENCODING_INDEX_UNKNOWN) {
74
7.71M
        gs_glyph glyph0 = gs_c_known_encode(ch, encoding_index);
75
7.71M
        gs_glyph glyph1 = pdfont->u.simple.Encoding[ch].glyph;
76
7.71M
        gs_const_string str;
77
7.71M
        int code = gs_c_glyph_name(glyph0, &str);
78
79
7.71M
        if (code < 0)
80
0
            return code; /* Must not happen */
81
7.71M
        if (glyph1 != GS_NO_GLYPH) {
82
667k
            gs_const_string str2;
83
667k
            str2.data = pdfont->u.simple.Encoding[ch].data;
84
667k
            str2.size = pdfont->u.simple.Encoding[ch].size;
85
667k
            if (!strings_equal(&str, &str2))
86
73.9k
                return 1;
87
667k
        }
88
7.71M
    }
89
8.06M
    return 0;
90
8.16M
}
91
92
/* Find an index of a different encoding element. */
93
int
94
pdf_different_encoding_index(const pdf_font_resource_t *pdfont, int ch0)
95
30.7k
{
96
30.7k
    gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
97
30.7k
    int ch, code;
98
99
6.54M
    for (ch = ch0; ch < 256; ++ch) {
100
6.51M
        code = pdf_different_encoding_element(pdfont, ch, base_encoding);
101
6.51M
        if (code < 0)
102
0
            return code; /* Must not happen */
103
6.51M
        if (code)
104
7.39k
            break;
105
6.51M
    }
106
30.7k
    return ch;
107
30.7k
}
108
109
/* Check for unknown encode (simple fonts only). */
110
static bool
111
pdf_simple_font_needs_ToUnicode(gx_device_pdf *pdev, const pdf_font_resource_t *pdfont)
112
3.49k
{
113
3.49k
    int ch;
114
3.49k
    unsigned char mask = (pdfont->FontType == ft_encrypted || pdfont->FontType == ft_encrypted2
115
3.49k
                ? GS_C_PDF_GOOD_GLYPH_MASK : GS_C_PDF_GOOD_NON_SYMBOL_MASK);
116
117
3.49k
    if (pdfont->u.simple.Encoding == NULL)
118
0
        return true; /* Bitmap Type 3 fonts have no pdfont->u.simple.Encoding . */
119
3.49k
    if (pdfont->FontType == ft_TrueType)
120
        /*
121
            TrueType fonts are always written as symbolic, and so they do not have
122
            an Encoding entry (SVN revision 11735, bugs #690744, #691036, #691319).
123
            In this circumstance, write the ToUnicode map to get a searchable PDF.
124
        */
125
1.19k
        return true;
126
127
2.30k
    if (!pdev->ToUnicodeForStdEnc) {
128
0
        for (ch = 0; ch < 256; ++ch) {
129
0
            pdf_encoding_element_t *pet = &pdfont->u.simple.Encoding[ch];
130
0
            gs_glyph glyph = pet->glyph;
131
132
0
            if (glyph == GS_NO_GLYPH)
133
0
                continue;
134
0
            if (glyph < gs_c_min_std_encoding_glyph || glyph >= GS_MIN_CID_GLYPH) {
135
0
                if (pet->size == 0)
136
0
                    return true;
137
0
                glyph = gs_c_name_glyph(pet->data, pet->size);
138
0
                if (glyph == GS_NO_GLYPH)
139
0
                    return true;
140
0
            }
141
0
            glyph -= gs_c_min_std_encoding_glyph;
142
0
            if( glyph > GS_C_PDF_MAX_GOOD_GLYPH ||
143
0
               !(gs_c_pdf_glyph_type[glyph >> 2] & (mask << (( glyph & 3 )<<1) )))
144
0
              return true;
145
146
0
        }
147
0
        return false;
148
0
    } else
149
2.30k
        return true;
150
2.30k
}
151
152
/* Write Encoding differencrs. */
153
int
154
pdf_write_encoding(gx_device_pdf *pdev, const pdf_font_resource_t *pdfont, int64_t id, int ch)
155
8.49k
{
156
    /* Note : this truncates extended glyph names to original names. */
157
8.49k
    stream *s;
158
8.49k
    gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
159
8.49k
    const int sl = strlen(gx_extendeg_glyph_name_separator);
160
8.49k
    int prev = 256, code, cnt = 0;
161
162
8.49k
    pdf_open_separate(pdev, id, resourceEncoding);
163
8.49k
    s = pdev->strm;
164
8.49k
    stream_puts(s, "<</Type/Encoding");
165
8.49k
    if (base_encoding < 0 && pdev->ForOPDFRead)
166
0
        base_encoding = ENCODING_INDEX_STANDARD;
167
8.49k
    if (base_encoding > 0)
168
4.63k
        pprints1(s, "/BaseEncoding/%s", encoding_names[base_encoding]);
169
8.49k
    stream_puts(s, "/Differences[");
170
1.65M
    for (; ch < 256; ++ch) {
171
1.64M
        code = pdf_different_encoding_element(pdfont, ch, base_encoding);
172
1.64M
        if (code < 0)
173
0
            return code; /* Must not happen */
174
1.64M
        if (code == 0 && (pdfont->FontType == ft_user_defined ||
175
1.55M
            pdfont->FontType == ft_PCL_user_defined ||
176
1.55M
            pdfont->FontType == ft_MicroType ||
177
1.55M
            pdfont->FontType == ft_GL2_stick_user_defined ||
178
1.55M
            pdfont->FontType == ft_GL2_531)) {
179
            /* PDF 1.4 spec Appendix H Note 42 says that
180
             * Acrobat 4 can't properly handle Base Encoding.
181
             * Enforce writing differences against that.
182
             */
183
264k
            if (pdfont->used[ch >> 3] & 0x80 >> (ch & 7))
184
0
                if (pdfont->u.simple.Encoding[ch].size)
185
0
                    code = 1;
186
264k
        }
187
1.64M
        if (code) {
188
95.5k
            const byte *d = pdfont->u.simple.Encoding[ch].data;
189
95.5k
            int i, l = pdfont->u.simple.Encoding[ch].size;
190
191
95.5k
            if (pdev->HavePDFWidths) {
192
87.6k
                for (i = 0; i + sl < l; i++)
193
50.7k
                    if (!memcmp(d + i, gx_extendeg_glyph_name_separator, sl)) {
194
0
                        l = i;
195
0
                        break;
196
0
                    }
197
36.9k
            }
198
95.5k
            if (ch != prev + 1) {
199
30.2k
                pprintd1(s, "\n%d", ch);
200
30.2k
                cnt = 1;
201
65.2k
            } else if (!(cnt++ & 15))
202
1.99k
                stream_puts(s, "\n");
203
95.5k
            pdf_put_name(pdev, d, l);
204
95.5k
            prev = ch;
205
95.5k
        }
206
1.64M
    }
207
8.49k
    stream_puts(s, "]>>\n");
208
8.49k
    pdf_end_separate(pdev, resourceEncoding);
209
8.49k
    return 0;
210
8.49k
}
211
212
/* Write Encoding reference. */
213
int
214
pdf_write_encoding_ref(gx_device_pdf *pdev,
215
          const pdf_font_resource_t *pdfont, int64_t id)
216
34.0k
{
217
34.0k
    stream *s = pdev->strm;
218
219
34.0k
    if (id != 0) {
220
10.6k
        pprinti64d1(s, "/Encoding %"PRId64" 0 R", id);
221
10.6k
        pdf_record_usage_by_parent(pdev, id, pdfont->object->id);
222
10.6k
    }
223
23.3k
    else if (pdfont->u.simple.BaseEncoding > 0) {
224
11.4k
        gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
225
11.4k
        pprints1(s, "/Encoding/%s", encoding_names[base_encoding]);
226
11.4k
    }
227
34.0k
    return 0;
228
34.0k
}
229
230
/* Write the Subtype and Encoding for a simple font. */
231
static int
232
pdf_write_simple_contents(gx_device_pdf *pdev,
233
                          const pdf_font_resource_t *pdfont)
234
30.7k
{
235
30.7k
    stream *s = pdev->strm;
236
30.7k
    int64_t diff_id = 0;
237
30.7k
    int ch = (pdfont->u.simple.Encoding ? 0 : 256);
238
30.7k
    int code = 0;
239
240
30.7k
    ch = pdf_different_encoding_index(pdfont, ch);
241
30.7k
    if (ch < 256)
242
7.39k
        diff_id = pdf_obj_ref(pdev);
243
30.7k
    code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
244
30.7k
    if (code < 0)
245
0
        return code;
246
30.7k
    if (pdfont->FontDescriptor == NULL || pdfont->FontDescriptor->embed)
247
30.7k
        pprints1(s, "/Subtype/%s>>\n",
248
30.7k
             (pdfont->FontType == ft_TrueType ? "TrueType" : "Type1"));
249
14
    else
250
14
        pprints1(s, "/Subtype/%s>>\n",
251
14
             (pdfont->FontDescriptor->FontType == ft_TrueType ? "TrueType" : "Type1"));
252
30.7k
    pdf_end_separate(pdev, resourceFont);
253
30.7k
    if (diff_id) {
254
7.39k
        mark_font_descriptor_symbolic(pdfont);
255
7.39k
        code = pdf_write_encoding(pdev, pdfont, diff_id, ch);
256
7.39k
        if (code < 0)
257
0
            return code;
258
7.39k
    }
259
30.7k
    return 0;
260
30.7k
}
261
262
/*
263
 * Write the W[2] entries for a CIDFont.  *pdfont is known to be a
264
 * CIDFont (type 0 or 2).
265
 */
266
static bool
267
pdf_compute_CIDFont_default_widths(const pdf_font_resource_t *pdfont, int wmode, int *pdw, int *pdv)
268
1.34k
{
269
1.34k
    psf_glyph_enum_t genum;
270
1.34k
    gs_glyph glyph;
271
1.34k
    ushort counts[1500]; /* Some CID fonts use vertical widths 1026 .*/
272
1.34k
    int dw_count = 0, i, dwi = 0, neg_count = 0, pos_count = 0;
273
1.34k
    double *w = (wmode ? pdfont->u.cidfont.Widths2 : pdfont->Widths);
274
275
    /* We don't wont to scan for both negative and positive widths,
276
     * to save the C stack space.
277
     * Doubtly they both are used in same font.
278
     * So just count positive and negative widths separately
279
     * and use the corresponding sign.
280
     * fixme : implement 2 hystograms.
281
     */
282
1.34k
    psf_enumerate_bits_begin(&genum, NULL,
283
1.34k
                             wmode ? pdfont->u.cidfont.used2 : pdfont->used,
284
1.34k
                             pdfont->count, GLYPH_SPACE_INDEX);
285
1.34k
    memset(counts, 0, sizeof(counts));
286
28.4k
    while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
287
27.0k
        int i = glyph - GS_MIN_CID_GLYPH;
288
289
27.0k
        if ( i < pdfont->count) { /* safety */
290
27.0k
            int width = (int)(w[i] + 0.5);
291
292
27.0k
            counts[min(any_abs(width), countof(counts) - 1)]++;
293
27.0k
            if (width > 0)
294
25.8k
                pos_count++;
295
1.27k
            else if (width < 0)
296
139
                neg_count++;
297
27.0k
        }
298
27.0k
    }
299
2.01M
    for (i = 1; i < countof(counts); ++i)
300
2.01M
        if (counts[i] > dw_count)
301
2.22k
            dwi = i, dw_count = counts[i];
302
1.34k
    *pdw = (neg_count > pos_count ? -dwi : dwi);
303
1.34k
    *pdv = 0;
304
1.34k
    if (wmode) {
305
18
        psf_enumerate_glyphs_reset(&genum);
306
18
        while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
307
18
            int i = glyph - GS_MIN_CID_GLYPH;
308
309
18
            if ( i < pdfont->count) { /* safety */
310
18
                int width = (int)(w[i] + 0.5);
311
312
18
                if (min(any_abs(width), countof(counts) - 1) == any_abs(dwi)) {
313
18
                    *pdv = (int)(pdfont->u.cidfont.v[i * 2 + 1] + 0.5);
314
18
                    break;
315
18
                }
316
18
            }
317
18
        }
318
18
    }
319
1.34k
    return (dw_count + counts[0] > 0);
320
1.34k
}
321
322
/*
323
 * Write the [D]W[2] entries for a CIDFont.  *pdfont is known to be a
324
 * CIDFont (type 0 or 2).
325
 */
326
static int
327
pdf_write_CIDFont_widths(gx_device_pdf *pdev,
328
                         const pdf_font_resource_t *pdfont, int wmode)
329
1.34k
{
330
    /*
331
     * The values of the CIDFont width keys are as follows:
332
     *   DW = w (default 0)
333
     *   W = [{c [w ...] | cfirst clast w}*]
334
     *   DW2 = [vy w1y] (default [880 -1000])
335
     *   W2 = [{c [w1y vx vy ...] | cfirst clast w1y vx vy}*]
336
     */
337
1.34k
    stream *s = pdev->strm;
338
1.34k
    psf_glyph_enum_t genum;
339
1.34k
    gs_glyph glyph;
340
1.34k
    int dw = 0, dv = 0, prev = -2;
341
1.34k
    const char *Widths_key = (wmode ? "/W2" : "/W");
342
1.34k
    double *w = (wmode ? pdfont->u.cidfont.Widths2 : pdfont->Widths);
343
344
    /* Compute and write default width : */
345
1.34k
    if (pdf_compute_CIDFont_default_widths(pdfont, wmode, &dw, &dv)) {
346
1.34k
        if (wmode) {
347
18
            pprintd2(s, "/DW2 [%d %d]\n", dv, dw);
348
18
        } else
349
1.32k
            pprintd1(s, "/DW %d\n", dw);
350
1.34k
    }
351
352
    /*
353
     * Now write all widths different from the default one.  Currently we make no
354
     * attempt to optimize this: we write every width individually.
355
     */
356
1.34k
    psf_enumerate_bits_begin(&genum, NULL,
357
1.34k
                             wmode ? pdfont->u.cidfont.used2 : pdfont->used,
358
1.34k
                             pdfont->count, GLYPH_SPACE_INDEX);
359
1.34k
    {
360
28.4k
        while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
361
27.0k
            int cid = glyph - GS_MIN_CID_GLYPH;
362
27.0k
            int width = (int)(w[cid] + 0.5);
363
364
      /* Must write zero widths - see test file of the bug Bug 687681. */
365
      /* We don't enumerate unused glyphs here due to pdfont->used. */
366
      /* if (width == 0)
367
                continue; */ /* Don't write for unused glyphs. */
368
27.0k
            { /* Check whether copied font really have this glyph.
369
                   debugged with 401-01.ps, which uses undefined CIDs. */
370
27.0k
                gs_font_base *pfont = pdf_font_resource_font(pdfont, false);
371
27.0k
                gs_glyph_info_t info;
372
373
27.0k
                if (pfont->FontType == ft_TrueType) {
374
                    /* We're converting a Type 42 into CIDFontType2. */
375
                    /* We know that CIDs equal to char codes. */
376
0
                    gs_glyph glyph1;
377
0
                    int ch = glyph & 0xff;
378
379
0
                    glyph1 = pfont->procs.encode_char((gs_font *)pfont, ch, GLYPH_SPACE_NAME);
380
0
                    if (cid == 0 && glyph1 == GS_NO_GLYPH)
381
0
                        glyph1 = copied_get_notdef((gs_font *)pdf_font_resource_font(pdfont, false));
382
0
                    if (glyph1 == GS_NO_GLYPH)
383
0
                        continue;
384
0
                    if (pfont->procs.glyph_info((gs_font *)pfont, glyph1, NULL, 0, &info) < 0)
385
0
                        continue;
386
27.0k
                } else if (pfont->procs.glyph_info((gs_font *)pfont, glyph, NULL, 0, &info) < 0)
387
221
                    continue;
388
27.0k
            }
389
26.8k
            if (cid == prev + 1) {
390
8.59k
                if (wmode) {
391
2
                    int vx = (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5);
392
2
                    int vy = (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5);
393
394
2
                    pprintd3(s, "\n%d %d %d", width, vx, vy);
395
2
                } else
396
8.59k
                    pprintd1(s, "\n%d", width);
397
18.2k
            } else if (pdev->PDFA == 0 && width == dw &&
398
18.2k
                    (!wmode || (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5) ==
399
45
                                (int)(pdfont->Widths[cid] / 2 + 0.5)) &&
400
18.2k
                    (!wmode || (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5) == dv))
401
9.12k
                continue;
402
9.13k
            else {
403
9.13k
                if (prev >= 0)
404
8.19k
                    stream_puts(s, "]\n");
405
933
                else {
406
933
                    stream_puts(s, Widths_key);
407
933
                    stream_puts(s, "[");
408
933
                }
409
9.13k
                if (wmode) {
410
127
                    int vx = (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5);
411
127
                    int vy = (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5);
412
413
127
                    pprintd4(s, "%d[%d %d %d", cid, width, vx, vy);
414
127
                } else
415
9.00k
                    pprintd2(s, "%d[%d", cid, width);
416
9.13k
            }
417
17.7k
            prev = cid;
418
17.7k
        }
419
1.34k
        if (prev >= 0)
420
933
            stream_puts(s, "]]\n");
421
1.34k
    }
422
423
1.34k
    return 0;
424
1.34k
}
425
426
/* ---------------- Specific FontTypes ---------------- */
427
428
/* Write the contents of a Type 0 font resource. */
429
int
430
pdf_write_contents_type0(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
431
1.32k
{
432
1.32k
    stream *s = pdev->strm;
433
434
    /*
435
     * The Encoding name might be missing if an error occurred when
436
     * creating the font resource.
437
     */
438
1.32k
    if (pdfont->u.type0.Encoding_name[0])
439
1.32k
        pprints1(s, "/Encoding %s", pdfont->u.type0.Encoding_name);
440
1.32k
    pprinti64d1(s, "/DescendantFonts[%"PRId64" 0 R]",
441
1.32k
              pdf_font_id(pdfont->u.type0.DescendantFont));
442
1.32k
    stream_puts(s, "/Subtype/Type0>>\n");
443
1.32k
    pdf_end_separate(pdev, resourceFont);
444
1.32k
    return 0;
445
1.32k
}
446
447
/*
448
 * Finish writing the contents of a Type 3 font resource (FontBBox, Widths,
449
 * Subtype).
450
 */
451
int
452
pdf_finish_write_contents_type3(gx_device_pdf *pdev,
453
                                pdf_font_resource_t *pdfont)
454
3.24k
{
455
3.24k
    stream *s = pdev->strm;
456
457
3.24k
    pdf_write_font_bbox_float(pdev, &pdfont->u.simple.s.type3.FontBBox);
458
3.24k
    pdf_write_Widths(pdev, pdfont->u.simple.FirstChar,
459
3.24k
                    pdfont->u.simple.LastChar, pdfont->Widths);
460
3.24k
    stream_puts(s, "/Subtype/Type3>>\n");
461
3.24k
    pdf_end_separate(pdev, resourceFont);
462
3.24k
    return 0;
463
3.24k
}
464
465
/* Write the contents of a standard (base 14) font resource. */
466
int
467
pdf_write_contents_std(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
468
3.82k
{
469
3.82k
    return pdf_write_simple_contents(pdev, pdfont);
470
3.82k
}
471
472
/* Write the contents of a simple (Type 1 or Type 42) font resource. */
473
int
474
pdf_write_contents_simple(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
475
26.9k
{
476
26.9k
    pdf_write_Widths(pdev, pdfont->u.simple.FirstChar,
477
26.9k
                     pdfont->u.simple.LastChar, pdfont->Widths);
478
26.9k
    return pdf_write_simple_contents(pdev, pdfont);
479
26.9k
}
480
481
/* Write the contents of a CIDFont resource. */
482
static int
483
write_contents_cid_common(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
484
                          int subtype)
485
1.32k
{
486
    /* Write [D]W[2], CIDSystemInfo, and Subtype, and close the object. */
487
1.32k
    stream *s = pdev->strm;
488
1.32k
    int code;
489
490
1.32k
    if (pdfont->Widths != 0) {
491
1.32k
        code = pdf_write_CIDFont_widths(pdev, pdfont, 0);
492
1.32k
        if (code < 0)
493
0
            return code;
494
1.32k
    } else {
495
        /* With a vertical font, the viewer uses /DW
496
           to determine glyph width to compute its v-vector. */
497
0
        stream_puts(s, "/DW 0\n");
498
0
    }
499
1.32k
    if (pdfont->u.cidfont.Widths2 != 0) {
500
18
        code = pdf_write_CIDFont_widths(pdev, pdfont, 1);
501
18
        if (code < 0)
502
0
            return code;
503
18
    }
504
1.32k
    if (pdfont->u.cidfont.CIDSystemInfo_id)
505
1.32k
        pprinti64d1(s, "/CIDSystemInfo %"PRId64" 0 R",
506
1.32k
                  pdfont->u.cidfont.CIDSystemInfo_id);
507
1.32k
    pprintd1(s, "/Subtype/CIDFontType%d>>\n", subtype);
508
1.32k
    pdf_end_separate(pdev, resourceFont);
509
1.32k
    return 0;
510
1.32k
}
511
int
512
pdf_write_contents_cid0(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
513
166
{
514
166
    return write_contents_cid_common(pdev, pdfont, 0);
515
166
}
516
int
517
pdf_write_contents_cid2(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
518
1.15k
{
519
1.15k
    int count = pdfont->count;
520
1.15k
    int64_t map_id = 0;
521
1.15k
    psf_glyph_enum_t genum;
522
1.15k
    gs_glyph glyph;
523
1.15k
    int code;
524
525
    /* Check for the identity CIDMap. */
526
1.15k
    psf_enumerate_bits_begin(&genum, NULL, pdfont->used, count,
527
1.15k
                             GLYPH_SPACE_INDEX);
528
20.1k
    while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
529
19.1k
        int cid = glyph - GS_MIN_CID_GLYPH;
530
19.1k
        int gid = pdfont->u.cidfont.CIDToGIDMap[cid];
531
532
19.1k
        if (gid != cid) { /* non-identity map */
533
169
            map_id = pdf_obj_ref(pdev);
534
169
            pprinti64d1(pdev->strm, "/CIDToGIDMap %"PRId64" 0 R\n", map_id);
535
169
            break;
536
169
        }
537
19.1k
    }
538
539
1.15k
    if (map_id == 0 && pdf_font_descriptor_embedding(pdfont->FontDescriptor)) {
540
989
        code = stream_puts(pdev->strm, "/CIDToGIDMap /Identity\n");
541
989
        if (code < 0)
542
0
            return code;
543
989
    }
544
545
1.15k
    code = write_contents_cid_common(pdev, pdfont, 2);
546
1.15k
    if (code < 0)
547
0
        return code;
548
549
1.15k
    if (map_id && pdf_font_descriptor_embedding(pdfont->FontDescriptor)) {
550
169
        pdf_data_writer_t writer;
551
169
        int i;
552
553
169
        pdf_begin_data_stream(pdev, &writer,
554
169
            DATA_STREAM_BINARY | (pdev->CompressFonts ? DATA_STREAM_COMPRESS : 0),
555
                    /* Don't set DATA_STREAM_ENCRYPT since we write to a temporary file.
556
                       See comment in pdf_begin_encrypt. */
557
169
                    map_id);
558
7.02M
        for (i = 0; i < pdfont->u.cidfont.CIDToGIDMapLength; ++i) {
559
7.02M
            uint gid = pdfont->u.cidfont.CIDToGIDMap[i];
560
561
7.02M
            stream_putc(writer.binary.strm, (byte)(gid >> 8));
562
7.02M
            stream_putc(writer.binary.strm, (byte)(gid));
563
7.02M
        }
564
169
        code = pdf_end_data(&writer);
565
169
    }
566
1.15k
    return code;
567
1.15k
}
568
569
/* ---------------- External entries ---------------- */
570
571
/* Write a font resource. */
572
static int
573
pdf_write_font_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
574
36.6k
{
575
36.6k
    stream *s;
576
36.6k
    cos_dict_t *pcd_Resources = NULL;
577
36.6k
    char *base14_name = NULL;
578
36.6k
    int64_t id;
579
580
36.6k
    if (pdfont->cmap_ToUnicode != NULL && pdfont->res_ToUnicode == NULL)
581
4.46k
        if (pdfont->FontType == ft_composite ||
582
4.46k
            ((pdfont->FontType == ft_encrypted || pdfont->FontType == ft_encrypted2 ||
583
3.49k
                pdfont->FontType == ft_TrueType || pdfont->FontType == ft_user_defined ||
584
3.49k
                pdfont->FontType == ft_GL2_stick_user_defined || pdfont->FontType == ft_PCL_user_defined ||
585
3.49k
                pdfont->FontType == ft_MicroType || pdfont->FontType == ft_GL2_531) &&
586
3.49k
                pdf_simple_font_needs_ToUnicode(pdev, pdfont))
587
4.46k
           ) {
588
4.46k
            pdf_resource_t *prcmap;
589
4.46k
            int code = pdf_cmap_alloc(pdev, pdfont->cmap_ToUnicode, &prcmap, -1);
590
591
4.46k
            if (code < 0)
592
0
                return code;
593
4.46k
            pdfont->res_ToUnicode = prcmap;
594
4.46k
        }
595
36.6k
    if (pdev->CompatibilityLevel >= 1.2 &&
596
36.6k
            (pdfont->FontType == ft_user_defined ||
597
36.6k
            pdfont->FontType == ft_PCL_user_defined ||
598
36.6k
            pdfont->FontType == ft_MicroType ||
599
36.6k
            pdfont->FontType == ft_GL2_stick_user_defined ||
600
36.6k
            pdfont->FontType == ft_GL2_531) &&
601
36.6k
            pdfont->u.simple.s.type3.Resources != NULL &&
602
36.6k
            pdfont->u.simple.s.type3.Resources->elements != NULL) {
603
207
        int code;
604
605
207
        pcd_Resources = pdfont->u.simple.s.type3.Resources;
606
207
        pcd_Resources->id = pdf_obj_ref(pdev);
607
207
        pdf_open_separate(pdev, pcd_Resources->id, resourceFont);
608
207
        code = COS_WRITE(pcd_Resources, pdev);
609
207
        if (code < 0)
610
0
            return code;
611
207
        pdf_end_separate(pdev, resourceFont);
612
207
    }
613
36.6k
    pdf_open_separate(pdev, pdf_font_id(pdfont), resourceFont);
614
36.6k
    s = pdev->strm;
615
36.6k
    stream_puts(s, "<<");
616
36.6k
    if (pdfont->BaseFont.size > 0) {
617
33.4k
        stream_puts(s, "/BaseFont");
618
33.4k
        if (pdfont->FontDescriptor && !pdf_font_descriptor_embedding(pdfont->FontDescriptor)
619
33.4k
            && (base14_name = (char *)pdf_find_base14_name((byte *)pdfont->BaseFont.data, (unsigned int)pdfont->BaseFont.size)))
620
0
            pdf_put_name(pdev, (byte *)base14_name, (unsigned int)strlen(base14_name));
621
33.4k
        else
622
33.4k
            pdf_put_name(pdev, (byte *)pdfont->BaseFont.data, pdfont->BaseFont.size);
623
33.4k
    }
624
36.6k
    if (pdfont->FontDescriptor) {
625
28.2k
        id = pdf_font_descriptor_id(pdfont->FontDescriptor);
626
28.2k
        pprinti64d1(s, "/FontDescriptor %"PRId64" 0 R", id);
627
28.2k
        if (pdev->Linearise) {
628
0
            pdf_set_font_descriptor_usage(pdev, pdfont->object->id, pdfont->FontDescriptor);
629
0
        }
630
28.2k
    }
631
36.6k
    if (pdfont->res_ToUnicode) {
632
4.46k
        id = pdf_resource_id((const pdf_resource_t *)pdfont->res_ToUnicode);
633
4.46k
        pprinti64d1(s, "/ToUnicode %"PRId64" 0 R", id);
634
4.46k
        pdf_record_usage_by_parent(pdev, id, pdfont->object->id);
635
4.46k
    }
636
36.6k
    if (pdev->CompatibilityLevel > 1.0)
637
36.6k
        stream_puts(s, "/Type/Font\n");
638
0
    else
639
0
        pprinti64d1(s, "/Type/Font/Name/R%"PRId64"\n", pdf_font_id(pdfont));
640
36.6k
    if (pdev->ForOPDFRead && pdfont->global)
641
0
        stream_puts(s, "/.Global true\n");
642
36.6k
    if (pcd_Resources != NULL) {
643
207
        id = pcd_Resources->id;
644
207
        pprinti64d1(s, "/Resources %"PRId64" 0 R\n", id);
645
207
        pdf_record_usage_by_parent(pdev, id, pdfont->object->id);
646
207
    }
647
36.6k
    return pdfont->write_contents(pdev, pdfont);
648
36.6k
}
649
650
/*
651
 * Close the text-related parts of a document, including writing out font
652
 * and related resources.
653
 */
654
int
655
write_font_resources(gx_device_pdf *pdev, pdf_resource_list_t *prlist)
656
83.7k
{
657
83.7k
    int j;
658
83.7k
    pdf_resource_t *pres;
659
660
1.42M
    for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
661
1.38M
        for (pres = prlist->chains[j]; pres != 0; pres = pres->next) {
662
41.9k
            pdf_font_resource_t *const pdfont = (pdf_font_resource_t *)pres;
663
664
41.9k
            if (pdf_resource_id(pres) != -1) {
665
36.6k
                int code = pdf_compute_BaseFont(pdev, pdfont, true);
666
667
36.6k
                if (code < 0)
668
0
                    return code;
669
36.6k
                code = pdf_write_font_resource(pdev, pdfont);
670
36.6k
                if (code < 0)
671
0
                    return code;
672
36.6k
                pdfont->object->written = true;
673
36.6k
            }
674
41.9k
        }
675
83.7k
    return 0;
676
83.7k
}
677
int
678
pdf_finish_resources(gx_device_pdf *pdev, pdf_resource_type_t type,
679
                        int (*finish_proc)(gx_device_pdf *,
680
                                           pdf_resource_t *))
681
125k
{
682
125k
    int j, ecode = 0;
683
125k
    pdf_resource_t *pres;
684
685
2.13M
    for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
686
2.00M
        for (pres = pdev->resources[type].chains[j];
687
2.11M
             pres != 0; pres = pres->next
688
2.00M
             ) {
689
107k
            int code = finish_proc(pdev, pres);
690
691
107k
            if (code < 0)
692
152
                ecode = code;
693
107k
        }
694
125k
    return ecode;
695
125k
}
696
697
/* ================ CMap resource writing ================ */
698
699
/*
700
 * Write the CIDSystemInfo for a CIDFont or a CMap.
701
 */
702
static int
703
pdf_write_cid_system_info_to_stream(gx_device_pdf *pdev, stream *s,
704
                          const gs_cid_system_info_t *pcidsi, gs_id object_id)
705
1.41k
{
706
1.41k
    byte *Registry = NULL, *Ordering = NULL;
707
1.41k
    int code = 0;
708
709
1.41k
    Registry = gs_alloc_bytes(pdev->pdf_memory, pcidsi->Registry.size, "temporary buffer for Registry");
710
1.41k
    if (!Registry)
711
0
        return(gs_note_error(gs_error_VMerror));
712
1.41k
    Ordering = gs_alloc_bytes(pdev->pdf_memory, pcidsi->Ordering.size, "temporary buffer for Registry");
713
1.41k
    if (!Ordering) {
714
0
        gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
715
0
        return(gs_note_error(gs_error_VMerror));
716
0
    }
717
1.41k
    memcpy(Registry, pcidsi->Registry.data, pcidsi->Registry.size);
718
1.41k
    memcpy(Ordering, pcidsi->Ordering.data, pcidsi->Ordering.size);
719
1.41k
    if (pdev->KeyLength && object_id != 0) {
720
0
        stream_arcfour_state sarc4;
721
0
        int code;
722
723
0
        code = pdf_encrypt_init(pdev, object_id, &sarc4);
724
0
        if (code < 0) {
725
0
            gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
726
0
            gs_free_object(pdev->pdf_memory, Ordering, "free temporary Ordering buffer");
727
0
            return(gs_note_error(code));
728
0
        }
729
0
        s_arcfour_process_buffer(&sarc4, Registry, pcidsi->Registry.size);
730
0
        code = pdf_encrypt_init(pdev, object_id, &sarc4);
731
0
        if (code < 0) {
732
0
            gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
733
0
            gs_free_object(pdev->pdf_memory, Ordering, "free temporary Ordering buffer");
734
0
            return(gs_note_error(code));
735
0
        }
736
0
        s_arcfour_process_buffer(&sarc4, Ordering, pcidsi->Ordering.size);
737
0
    }
738
1.41k
    code = stream_puts(s, "<<\n/Registry");
739
1.41k
    if (code < 0)
740
0
        goto error;
741
1.41k
    s_write_ps_string(s, Registry, pcidsi->Registry.size, PRINT_HEX_NOT_OK);
742
1.41k
    code = stream_puts(s, "\n/Ordering");
743
1.41k
    if(code < 0)
744
0
        goto error;
745
1.41k
    s_write_ps_string(s, Ordering, pcidsi->Ordering.size, PRINT_HEX_NOT_OK);
746
1.41k
    pprintd1(s, "\n/Supplement %d\n>>\n", pcidsi->Supplement);
747
1.41k
error:
748
1.41k
    gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
749
1.41k
    gs_free_object(pdev->pdf_memory, Ordering, "free temporary Ordering buffer");
750
1.41k
    return code;
751
1.41k
}
752
753
int
754
pdf_write_cid_system_info(gx_device_pdf *pdev,
755
                          const gs_cid_system_info_t *pcidsi, gs_id object_id)
756
1.35k
{
757
1.35k
    return pdf_write_cid_system_info_to_stream(pdev, pdev->strm, pcidsi, object_id);
758
1.35k
}
759
760
int
761
pdf_write_cid_systemInfo_separate(gx_device_pdf *pdev, const gs_cid_system_info_t *pcidsi, int64_t *id)
762
1.35k
{
763
1.35k
    int code;
764
765
1.35k
    *id = pdf_begin_separate(pdev, resourceCIDSystemInfo);
766
1.35k
    code = pdf_write_cid_system_info(pdev, pcidsi, *id);
767
1.35k
    pdf_end_separate(pdev, resourceCIDSystemInfo);
768
1.35k
    return code;
769
1.35k
}
770
771
/*
772
 * Write a CMap resource.  We pass the CMap object as well as the resource,
773
 * because we write CMaps when they are created.
774
 */
775
int
776
pdf_write_cmap(gx_device_pdf *pdev, const gs_cmap_t *pcmap,
777
               pdf_resource_t **ppres /*CMap*/, int font_index_only)
778
4.52k
{
779
4.52k
    int code;
780
4.52k
    pdf_data_writer_t writer;
781
4.52k
    gs_const_string alt_cmap_name;
782
4.52k
    const gs_const_string *cmap_name = &pcmap->CMapName;
783
784
4.52k
    code = pdf_begin_data_stream(pdev, &writer,
785
4.52k
                                 DATA_STREAM_NOT_BINARY |
786
                            /* Don't set DATA_STREAM_ENCRYPT since we write to a temporary file.
787
                               See comment in pdf_begin_encrypt. */
788
4.52k
                                 (pdev->CompressFonts ?
789
4.52k
                                  DATA_STREAM_COMPRESS : 0), gs_no_id);
790
4.52k
    if (code < 0)
791
0
        return code;
792
4.52k
    *ppres = writer.pres;
793
4.52k
    writer.pres->where_used = 0; /* CMap isn't a PDF resource. */
794
4.52k
    if (!pcmap->ToUnicode) {
795
60
        byte *buf = NULL;
796
60
        uint64_t buflen = 0;
797
60
        cos_dict_t *pcd = (cos_dict_t *)writer.pres->object;
798
60
        stream s;
799
800
        /* We use 'buf' for the stream 's' below and that needs to have some extra
801
         * space for the CIDSystemInfo. We also need an extra byte for the leading '/'
802
         * 100 bytes is ample for the overhead.
803
         */
804
60
        buflen = pcmap->CIDSystemInfo->Registry.size + pcmap->CIDSystemInfo->Ordering.size + pcmap->CMapName.size + 100;
805
60
        if (buflen > max_uint)
806
0
            return_error(gs_error_limitcheck);
807
808
60
        buf = gs_alloc_bytes(pdev->memory, buflen, "pdf_write_cmap");
809
60
        if (buf == NULL)
810
0
            return_error(gs_error_VMerror);
811
812
60
        code = cos_dict_put_c_key_int(pcd, "/WMode", pcmap->WMode);
813
60
        if (code < 0) {
814
0
            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
815
0
            return code;
816
0
        }
817
60
        buf[0] = '/';
818
60
        memcpy(buf + 1, pcmap->CMapName.data, pcmap->CMapName.size);
819
60
        code = cos_dict_put_c_key_string(pcd, "/CMapName",
820
60
                        buf, pcmap->CMapName.size + 1);
821
60
        if (code < 0) {
822
0
            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
823
0
            return code;
824
0
        }
825
60
        s_init(&s, pdev->memory);
826
60
        swrite_string(&s, buf, buflen);
827
60
        code = pdf_write_cid_system_info_to_stream(pdev, &s, pcmap->CIDSystemInfo, 0);
828
60
        if (code < 0) {
829
0
            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
830
0
            return code;
831
0
        }
832
60
        code = cos_dict_put_c_key_string(pcd, "/CIDSystemInfo",
833
60
                        buf, stell(&s));
834
60
        if (code < 0) {
835
0
            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
836
0
            return code;
837
0
        }
838
60
        code = cos_dict_put_string_copy(pcd, "/Type", "/CMap");
839
60
        if (code < 0) {
840
0
            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
841
0
            return code;
842
0
        }
843
60
        gs_free_object(pdev->memory, buf, "pdf_write_cmap");
844
60
    }
845
4.52k
    if (pcmap->CMapName.size == 0) {
846
        /* Create an arbitrary name (for ToUnicode CMap). */
847
4.46k
        alt_cmap_name.data = (byte *)(*ppres)->rname;
848
4.46k
        alt_cmap_name.size = strlen((*ppres)->rname);
849
4.46k
        cmap_name = &alt_cmap_name;
850
4.46k
    }
851
4.52k
    code = psf_write_cmap(pdev->memory, writer.binary.strm, pcmap,
852
4.52k
                          pdf_put_name_chars_proc(pdev),
853
4.52k
                          cmap_name, font_index_only);
854
4.52k
    if (code < 0)
855
0
        return code;
856
4.52k
    code = pdf_end_data(&writer);
857
4.52k
    if (code < 0)
858
0
        return code;
859
4.52k
    return code;
860
4.52k
}
861
862
static const char *OneByteIdentityH[] = {
863
    "/CIDInit /ProcSet findresource begin",
864
    "12 dict begin",
865
    "begincmap",
866
    "/CIDSystemInfo 3 dict dup begin",
867
      "/Registry (Adobe) def",
868
      "/Ordering (Identity) def",
869
      "/Supplement 0 def",
870
    "end def",
871
    "/CMapName /OneByteIdentityH def",
872
    "/CMapVersion 1.000 def",
873
    "/CMapType 1 def",
874
    "/UIDOffset 0 def",
875
    "/XUID [1 10 25404 9999] def",
876
    "/WMode 0 def",
877
    "1 begincodespacerange",
878
    "<00> <FF>",
879
    "endcodespacerange",
880
    "1 begincidrange",
881
    "<00> <FF> 0",
882
    "endcidrange",
883
    "endcmap",
884
    "CMapName currentdict /CMap defineresource pop",
885
    "end",
886
    "end",
887
NULL};
888
889
/*
890
 * Write OneByteIdentityH CMap.
891
 */
892
int
893
pdf_write_OneByteIdentityH(gx_device_pdf *pdev)
894
0
{
895
0
    int code, i;
896
0
    pdf_data_writer_t writer;
897
0
    cos_dict_t *pcd;
898
0
    char buf[200];
899
0
    static const gs_cid_system_info_t cidsi = {{(const byte *)"Adobe", 5}, {(const byte *)"Identity", 8}, 0};
900
0
    int64_t id;
901
902
0
    if (pdev->IdentityCIDSystemInfo_id == gs_no_id) {
903
0
        code = pdf_write_cid_systemInfo_separate(pdev, &cidsi, &id);
904
0
        if (code < 0)
905
0
            return code;
906
0
        pdev->IdentityCIDSystemInfo_id = id;
907
0
    }
908
0
    if (pdev->OneByteIdentityH != NULL)
909
0
        return 0;
910
0
    code = pdf_begin_data_stream(pdev, &writer,
911
0
                                 DATA_STREAM_NOT_BINARY |
912
                            /* Don't set DATA_STREAM_ENCRYPT since we write to a temporary file.
913
                               See comment in pdf_begin_encrypt. */
914
0
                                 (pdev->CompressFonts ?
915
0
                                  DATA_STREAM_COMPRESS : 0), gs_no_id);
916
0
    if (code < 0)
917
0
        return code;
918
0
    pdev->OneByteIdentityH = writer.pres;
919
0
    pcd = (cos_dict_t *)writer.pres->object;
920
0
    code = cos_dict_put_string_copy(pcd, "/CMapName", "/OneByteIdentityH");
921
0
    if (code < 0)
922
0
        return code;
923
0
    gs_snprintf(buf, sizeof(buf), "%ld 0 R", pdev->IdentityCIDSystemInfo_id);
924
0
    code = cos_dict_put_string_copy(pcd, "/CIDSystemInfo", buf);
925
0
    if (code < 0)
926
0
        return code;
927
0
    code = cos_dict_put_string_copy(pcd, "/Type", "/CMap");
928
0
    if (code < 0)
929
0
        return code;
930
0
    for (i = 0; OneByteIdentityH[i]; i++) {
931
0
        stream_puts(pdev->strm, OneByteIdentityH[i]);
932
0
        stream_putc(pdev->strm, '\n');
933
0
    }
934
0
    return pdf_end_data(&writer);
935
0
}